使用聚合索引优化SQL查询

时间:2012-01-17 14:14:28

标签: mysql

我正在寻找可能的最佳查询来获取给定记录集的最新日期,其中我需要过滤的字段是:

  • CreateDate:DATETIME
  • TransactionStatus:VARCHAR(10)
  • DocumentSeries:VARCHAR(45)

更简单的查询就是这个

SELECT MAX(CreateDate) FROM transactionsheaders WHERE TransactionStatus="N" AND DocumentSeries='Z';

当我使用说明时,我得到了

EXPLAIN(SELECT MAX(CreateDate) FROM transactionsheaders WHERE TransactionStatus="N" AND DocumentSeries='Z');
+----+-------------+---------------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table               | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+---------------------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | transactionsheaders | ALL  | NULL          | NULL | NULL    | NULL | 5752 | Using where |
+----+-------------+---------------------+------+---------------+------+---------+------+------+-------------+

总记录集5715。

好的,我没有使用索引,我正在使用text和datetime列...我想这不是一个简单的场景所以我决定在表中添加一个与DocumentSeries具有相同含义的列但是是一个int,所以查询将是:

SELECT MAX(CreateDate) FROM transactionsheaders WHERE TransactionStatus="N" AND DocumentSeriesUID=2;

并添加了一个索引,用

来聚合3列
ALTER TABLE `transactionsheaders` ADD INDEX `index_doc_series` (`DocumentSeriesUID` ASC, `CreateDate` ASC, `TransactionStatus` ASC);

并解释输出

+----+-------------+---------------------+------+------------------+------------------+---------+-------+------+--------------------------+
| id | select_type | table               | type | possible_keys    | key              | key_len | ref   | rows | Extra                    |
+----+-------------+---------------------+------+------------------+------------------+---------+-------+------+--------------------------+
|  1 | SIMPLE      | transactionsheaders | ref  | index_doc_series | index_doc_series | 4       | const | 2876 | Using where; Using index |
+----+-------------+---------------------+------+------------------+------------------+---------+-------+------+--------------------------+

Q1。嗯......显然我使用的数据较少,但如果我用相同的条件进行计数,我会得到5703个结果,所以,这有点令人困惑。我知道EXPLAIN估计查询需要获取的行数,但它怎么能关闭?

然后,我不需要同时获取所有内容,因此我的下一个测试是获取符合我的搜索条件的前10个结果

SELECT MAX(Q.CreateDate) FROM((SELECT CreateDate FROM transactionsheaders WHERE TransactionStatus="N" AND DocumentSeriesUID='2' ORDER BY CreateDate DESC LIMIT 10) as Q);

但......如果我使用ORDER BY,我不需要MAX而我只限制为1?

SELECT CreateDate FROM transactionsheaders WHERE TransactionStatus="N" AND DocumentSeriesUID='2' ORDER BY CreateDate DESC LIMIT 1;

和EXPLAIN产生与使用MAX的查询相同的结果。

嗯,所有这些只是问我如何优化这个查询?它是否已经通过唱指数进行了优化?我可以走得更远吗?

干杯

2 个答案:

答案 0 :(得分:2)

查询

SELECT MAX(CreateDate)
FROM transactionsheaders
WHERE TransactionStatus="N" AND DocumentSeriesUID=2;

索引应为(TransactionStatus, DocumentSeriesUID, CreateDate)(DocumentSeriesUID, TransactionStatus, CreateDate),具体取决于基数。首先使用字段上的条件,然后在找到的行中查找最大的CreateDate。

答案 1 :(得分:0)

定义多字段索引时,必须确保按照指定的顺序使用字段。

e.g。给定index(a,b,c),然后

... where a=?
... where a=? and b=?    
... where b=? and a=?
... where a=? and b=? and c=?

都可以使用索引,因为您已按照定义的顺序使用了索引的字段。在你的情况下,你已经完成了

... where a=? and c=?

并省略b,这会阻止使用该索引。将多字段索引中的字段视为“链接”。要能够到达索引中的“c”字段,您必须通过“b”,但是您没有在where子句中指定任何“b”字段。

请注意,如果索引字段有a,b,c,那么你的where子句只需要使用所有这些字段,字段在where子句中显示的实际顺序是无关紧要的 - 它是否存在字段很重要。

重新排列索引定义,使其变为a,c,b,或者为字段创建仅a,c的辅助索引。