我有两张桌子:
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
...
SAMPLES
中约有20,000行。对于每个样本,DATA
中有大约40,000行。 ASSAY_ID
中每个样本只出现一次DATA
。我需要在SAMPLE
中获取一部分样本,并计算DATA
中每个信号值的标准/ z分数值,按ASSAY_ID
进行分组。我正在尝试创建一个将被重复调用的存储过程,它将接受单个ASSAY_ID
值并返回预定义样本子集中所有样本的SAMPLE_ID
和ZSCORE
对。
给定一组给定化验的样本信号值(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
执行此计算吗?
答案 0 :(得分: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
更快)。而且,如果这是一个选项,我会尝试将分析与分区进行物理配置。