2013-01-10 173 views
3

的Z值我有兩個表: DATA的Oracle SQL:最有效的方法來計算分組數據

DATA_ID | SAMPLE_ID | ASSAY_ID | SIGNAL 
101  | 201  | 301  | 2.87964 
102  | 201  | 302  | 7.64623 
103  | 202  | 301  | 1.98473 
... 

而且SAMPLES

SAMPLE_ID | SAMPLE_NAME | CATEGORY 
201  | SAMP0001  | CAT A 
202  | SAMP0002  | CAT B 
203  | SAMP0003  | CAT A 
... 

有在SAMPLES約20000行。對於每個樣品,DATA中有大約40,000行。 DATA中的每個樣本每個ASSAY_ID恰好出現一次。我需要在SAMPLE中抽取一部分樣本,並計算DATA中每個信號值的標準/ z分數值,按ASSAY_ID分組。我正在嘗試創建一個將被重複調用的存儲過程,該過程將接受一個ASSAY_ID值,並返回SAMPLE_IDZSCORE對,用於預定義採樣子集中的所有采樣。

給定一組樣品信號值(X = [3.21, 4.56, 1.12, ..])對於給定的測定中,在這種情況下,標準/ z得分被計算爲

(X[i] - median(X))/(K * MAD) 

K是一個比例因子等於1.4826和MAD是中值調整後的偏差等於:

median(|X[i]-median(X)|) 

明白了嗎?好:)現在,使用SQL查詢執行此計算的最有效方法是什麼?執行時間很關鍵,因爲DATA中有近10億行,並且幾乎每個SIGNAL值都需要計算z分數。

這裏是我已經能夠拿出迄今最佳的查詢:

WITH BASE AS (
    SELECT 
     S.SAMPLE_ID, 
     D.SIGNAL 
    FROM 
     DATA D 
     JOIN SAMPLES S 
      ON D.SAMPLE_ID = S.SAMPLE_ID 
    WHERE 
     S.CATEGORY IN ('CAT A', 'CAT B') 
     AND D.ASSAY_ID = 12345 
     AND S.SAMPLE_NAME NOT IN ('SAMP0003', 'SAMP0005', 'SAMP0008')   
) 
SELECT 
    A.SAMPLE_ID, 
    (A.SIGNAL-B.MED)/(1.4826*C.MAD) AS ZSCORE 
FROM 
    BASE A, 
    (
     SELECT MEDIAN(X.SIGNAL) AS MED 
     FROM BASE X 
    ) B, 
    (
     SELECT MEDIAN(ABS(Y.SIGNAL-YY.MED)) AS MAD 
     FROM BASE Y, 
     (SELECT MEDIAN(SIGNAL) AS MED FROM BASE) YY 
    ) C 

是否有執行該查詢更有效的方式?

獎勵題:我可以寫一個SQL查詢,將在單個執行執行此計算爲每ASSAY_ID

回答

2

你可以看看:

SELECT ASSAY_ID, SAMPLE_ID, 
     (SIGNAL - MED)/(1.4826F * MAD) AS ZSCORE 
    FROM (
     SELECT ASSAY_ID, SAMPLE_ID, SIGNAL, MED, 
       MEDIAN(ABS(SIGNAL - MED)) OVER (PARTITION BY ASSAY_ID) AS MAD 
      FROM (
       SELECT ASSAY_ID, SAMPLE_ID, SIGNAL, 
         MEDIAN(SIGNAL) OVER (PARTITION BY ASSAY_ID) AS MED 
        FROM DATA D 
        JOIN SAMPLES S USING (SAMPLE_ID) 
       WHERE S.CATEGORY IN ('CAT A', 'CAT B') 
        AND S.SAMPLE_NAME NOT IN ('SAMP0003', 'SAMP0005', 'SAMP0008') 
        AND D.ASSAY_ID = 301 
       ) 
     ); 

它是正確的嗎?速度更快嗎?如果是這樣,只是刪除了獎金問題AND D.ASSAY_ID = 301條款:-)

在身體方面,我會考慮的信號(BINARY_FLOATBINARY_DOUBLE是所謂快於NUMBER)的數據類型。而且,如果這是一個選項,我會嘗試將分析與分區進行物理配置。

+0

謝謝,當我明天上班時,我會試試這個!假設這更快,爲什麼會這樣? – woemler

+1

沒有適當的數據我猜測了很多,但它看起來像'WITH'方法實現基本查詢到一個臨時表中,可以完全掃描四次。分析函數方法似乎可以通過對錶DATA的單次完整掃描而消除。 –

+0

一些快速測試表明此版本的查詢速度稍快,並且查詢計劃顯示成本略有下降。同樣重要的是,這是更簡潔的代碼和獎勵問題的一個很好的答案。謝謝! – woemler

相關問題