解释慢查询

时间:2014-05-15 17:45:33

标签: mysql

我们有下表

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_PVALUEMOST_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行。我们有两个问题:

  1. 为什么第一次查询执行需要这么长时间?我们假设这是因为某些操作系统缓存或分页问题,​​因为查询缓存已关闭,并且密切相关的查询(例如,用0.1替换0.05)也会第二次快速运行。

  2. 为什么这个查询需要大约3分钟,即使没有缓存,每个页面提取到磁盘?它只返回8行,并且索引不应该直接寻找这8行,因为前两个键位于where子句中的两个键上?为什么解释估计扫描280K行而不是8?我们在桌面上运行了一个OPTIMIZE,估计值仍然相同。                                                                                        同样令人困惑的是,强制在GWAS_T2D_PVALUE上单独使用索引时的解释会产生扫描44K行的估计值,并且(GWAS_T2D_PVALUE,MOST_DEL_SCORE)上的索引产生并估计扫描的32K行。根据我们对多列索引的理解,为什么2和3列索引的查询性能会有所不同,并且不应该都远远优于1列索引?

2 个答案:

答案 0 :(得分:2)

索引中的列是根据查询向后的,以及您在查询计划中看到using where的原因。

要调用陈旧的插图,请考虑电话簿。

您的查询为WHERE last_name < 'smith' AND first_name = 'john'

事实上,名字在每个排序的姓氏组中排序是没有实际价值的,因为我们仍然需要考虑目录的大部分人(史密斯之前的所有人)的所有人并评估他们的第一个在每个不同的姓氏中单独命名。这就是你的行估计如此之大的原因。

如果两个表达式都是相等比较,那么服务器确实可以直接转到8行。如果索引中最左边的列经过相等比较,第二列是&#34;小于&#34;比较,服务器可以再次直接转到相关的行,因为它们都将在索引中相邻。

具有相反顺序的两列的索引很可能会提供非常不同的性能。

通常,using wherekey的值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并停止。它不必经历第一个索引提供的所有其他组合。

只是一个建议,但我已经看到历史查询改进基于匹配条件的正确索引更具体,并在索引的后续列中更通用。