我们有下表
CREATE TABLE variant
(
id VARCHAR(105),
chrom VARCHAR(12),
condel_pred VARCHAR(11),
consequence VARCHAR(97),
dbsnp_id VARCHAR(23),
most_del_score INTEGER,
pos INTEGER,
polyphen_pred VARCHAR(17),
protein_change VARCHAR(39),
sift_pred VARCHAR(11),
_13k_t2d_aa_mac INTEGER,
_13k_t2d_aa_maf FLOAT,
_13k_t2d_aa_mina INTEGER,
_13k_t2d_aa_minu INTEGER,
_13k_t2d_ea_mac INTEGER,
_13k_t2d_ea_maf FLOAT,
_13k_t2d_ea_mina INTEGER,
_13k_t2d_ea_minu INTEGER,
_13k_t2d_eu_mac INTEGER,
_13k_t2d_eu_maf FLOAT,
_13k_t2d_eu_mina INTEGER,
_13k_t2d_eu_minu INTEGER,
_13k_t2d_het_carriers VARCHAR(4),
_13k_t2d_het_ethnicities VARCHAR(32),
_13k_t2d_hom_carriers VARCHAR(5),
_13k_t2d_hom_ethnicities VARCHAR(32),
_13k_t2d_hs_mac INTEGER,
_13k_t2d_hs_maf FLOAT,
_13k_t2d_hs_mina INTEGER,
_13k_t2d_hs_minu INTEGER,
_13k_t2d_sa_mac INTEGER,
_13k_t2d_sa_maf FLOAT,
_13k_t2d_sa_mina INTEGER,
_13k_t2d_sa_minu INTEGER,
closest_gene VARCHAR(16),
exchp_t2d_beta FLOAT,
exchp_t2d_direction VARCHAR(13),
exchp_t2d_maf FLOAT,
exchp_t2d_neff FLOAT,
exchp_t2d_p_value FLOAT,
gene VARCHAR(20),
in_exchp VARCHAR(1),
in_exseq VARCHAR(1),
in_gene VARCHAR(17),
qcfail INTEGER,
_13k_t2d_heta INTEGER,
_13k_t2d_hetu INTEGER,
_13k_t2d_homa INTEGER,
_13k_t2d_homu INTEGER,
_13k_t2d_mac INTEGER,
_13k_t2d_mina INTEGER,
_13k_t2d_minu INTEGER,
_13k_t2d_or_wald_dos_fe_iv FLOAT,
_13k_t2d_p_emmax_fe_iv FLOAT,
_13k_t2d_transcript_annot VARCHAR(10745),
gwas_t2d_effect_allele VARCHAR(1),
gwas_t2d_or FLOAT,
gwas_t2d_pvalue FLOAT,
gws_traits VARCHAR(43),
in_gwas VARCHAR(1),
_13k_t2d_aa_eaf FLOAT,
_13k_t2d_ea_eaf FLOAT,
_13k_t2d_sa_eaf FLOAT
)
有几个索引,但包括
GWAS_T2D_PVAL_MOST_DEL_13k_T2D_EA_MAF_IDX
位于(GWAS_T2D_PVALUE, MOST_DEL_SCORE, _13k_T2D_EA_MAF)
大约有6m行,有很多NULL数据,GWAS_T2D_PVALUE
和MOST_DEL_SCORE
对于相对较少的行(~40k行)一起非空。
我们正在观察运行以下查询时我们无法理解的性能
SELECT *
FROM VARIANT USE INDEX GWAS_T2D_PVAL_MOST_DEL_13k_T2D_EA_MAF_IDX)
WHERE GWAS_T2D_PVALUE < .05 AND MOST_DEL_SCORE = 1;
具有以下EXPLAIN:
+----+-------------+---------+-------+-------------------------------------------+-------------------------------------------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+-------------------------------------------+-------------------------------------------+---------+------+--------+-------------+
| 1 | SIMPLE | VARIANT | range | GWAS_T2D_PVAL_MOST_DEL_13k_T2D_EA_MAF_IDX | GWAS_T2D_PVAL_MOST_DEL_13k_T2D_EA_MAF_IDX | 10 | NULL | 280242 | Using where |
+----+-------------+---------+-------+-------------------------------------------+-------------------------------------------+---------+------+--------+-------------+
如果查询在一段时间内没有运行(例如8小时),则查询需要很长时间才能执行(约3分钟),但之后需要&lt; 1s并返回8行。我们有两个问题:
为什么第一次查询执行需要这么长时间?我们假设这是因为某些操作系统缓存或分页问题,因为查询缓存已关闭,并且密切相关的查询(例如,用0.1替换0.05)也会第二次快速运行。
为什么这个查询需要大约3分钟,即使没有缓存,每个页面提取到磁盘?它只返回8行,并且索引不应该直接寻找这8行,因为前两个键位于where子句中的两个键上?为什么解释估计扫描280K行而不是8?我们在桌面上运行了一个OPTIMIZE,估计值仍然相同。 同样令人困惑的是,强制在GWAS_T2D_PVALUE上单独使用索引时的解释会产生扫描44K行的估计值,并且(GWAS_T2D_PVALUE,MOST_DEL_SCORE)上的索引产生并估计扫描的32K行。根据我们对多列索引的理解,为什么2和3列索引的查询性能会有所不同,并且不应该都远远优于1列索引?
答案 0 :(得分:2)
索引中的列是根据查询向后的,以及您在查询计划中看到using where
的原因。
要调用陈旧的插图,请考虑电话簿。
您的查询为WHERE last_name < 'smith' AND first_name = 'john'
。
事实上,名字在每个排序的姓氏组中排序是没有实际价值的,因为我们仍然需要考虑目录的大部分人(史密斯之前的所有人)的所有人并评估他们的第一个在每个不同的姓氏中单独命名。这就是你的行估计如此之大的原因。
如果两个表达式都是相等比较,那么服务器确实可以直接转到8行。如果索引中最左边的列经过相等比较,第二列是&#34;小于&#34;比较,服务器可以再次直接转到相关的行,因为它们都将在索引中相邻。
具有相反顺序的两列的索引很可能会提供非常不同的性能。
通常,using where
中key
的值possible_keys
也显示意味着索引正在帮助一些,但服务器仍然需要评估索引找到的内容并消除其他内容在where子句中使用表达式的行。
对相同查询的响应速度越快,可能就是查询缓存的运行情况。对类似查询的响应速度越快,可能意味着您的innodb_buffer_pool_size
对于您的工作负载而言太小,缺少最佳索引所需的所有随机读取意味着在首次执行时会从磁盘加载到池中的大量页面。 / p>
答案 1 :(得分:2)
您现有的索引(GWAS_T2D_PVALUE,MOST_DEL_SCORE,_13k_T2D_EA_MAF),我会考虑将列的顺序反转为(MOST_DEL_SCORE,GWAS_T2D_PVALUE,_13k_T2D_EA_MAF),这就是原因。
将索引视为此。第一个索引具有GWAS_T2D_PVALUE。所以你有一个文件柜,所有这些值按值排序。然后,在这些常见值条目的每一个中,它将按顺序放入所有MOST_DEL_SCORE ...然后最终所有_13k在其中排序。因此,为了处理您的查询,您需要使用PVALUE&lt;来提取所有文件。 .05(或其他)。然后,您必须手动浏览每个文件,以获取MOST_DEL_SCORE为1的特定值并将其拉出的文件。
现在,尝试备用索引。您仍然有一个文件柜,但每个文件都是针对特定的MOST_DEL_SCORE。因此,如果您有20个分数,则需要查看20个文件。由于您总是在寻找ONE INSTANCE“MOST_DEL_SCORE = 1”,因此您只需要一个文件就可以了。您的下一个标准是GWAS_T2D_PVALUE&lt; 0.05。由于这些是索引的二级排序,所以这些都已准备就绪。因此引擎可以快速从第一个记录开始,然后上升到.05并停止。它不必经历第一个索引提供的所有其他组合。
只是一个建议,但我已经看到历史查询改进基于匹配条件的正确索引更具体,并在索引的后续列中更通用。