3

私は2つのテーブルを持っています: DATA

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
...

には約 20,000 行ありSAMPLESます。サンプルごとに、約 40,000 行ありDATAます。それぞれASSAY_IDは、 のサンプルごとに 1 回だけ発生しDATAます。のサンプルのサブセットを取得し、 でグループ化して、SAMPLEの各信号値の標準/Z スコア値を計算する必要があります。繰り返し呼び出されるストアド プロシージャを作成しようとしています。このストアド プロシージャは、定義済みのサンプル サブセット内のすべてのサンプルに対して単一の値と戻り値とペアを受け入れます。DATAASSAY_IDASSAY_IDSAMPLE_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 クエリを使用してこの計算を実行する最も効率的な方法は何ですか? 10 億行近くの行がDATAあり、ほぼすべての値について Z スコアを計算する必要があることを考えると、実行時間が重要SIGNALです。

これまでに思いついた最高のクエリは次のとおりです。

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 

このクエリを実行するより効率的な方法はありますか?

おまけの質問: 1 回の実行で EVERY に対してこの計算を実行する単一の SQL クエリを作成できますASSAY_IDか?

4

1 に答える 1

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_FLOATまたはBINARY_DOUBLE、より高速であると思われますNUMBER)。そして、これがオプションである場合、私はアッセイをパーティションと物理的に配置しようとします.

于 2013-01-10T23:49:34.960 に答える