6

我有一个大表,我必须从中选择大量行。

该表存储呼叫详细记录 (CDR)。例子:

+-------------+--------------+------+-----+---------------------+----------------+
| Field       | Type         | Null | Key | Default             | Extra          |
+-------------+--------------+------+-----+---------------------+----------------+
| id          | int(45)      | NO   | PRI | NULL                | auto_increment |
| calldate    | datetime     | NO   | MUL | 0000-00-00 00:00:00 |                |
| accountcode | varchar(100) | NO   |     |                     |                |
| other...    | varchar(45)  | NO   |     |                     |                |

由于我的查询会在特定日期查找客户电话,因此我在聚集索引中将 calldate 和 accountcode 一起编入索引,如下所示:

CREATE TABLE `cdr` (
  `id` int(45) NOT NULL AUTO_INCREMENT,
  `calldate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `accountcode` varchar(100) NOT NULL DEFAULT '',
   other fields...
PRIMARY KEY (`id`),
KEY `date_acc` (`calldate`,`accountcode`) USING BTREE
) ENGINE=MyISAM DEFAULT CHARSET=latin1

但是,在执行以下查询时,EXPLAIN 结果显示只使用了键的日期时间部分:

询问:

SELECT * 
FROM cdr
WHERE calldate > '2010-12-01'
  AND accountcode = 'xxxxxx';

解释结果:

+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+
| id | select_type | table | type  | possible_keys | key      | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | cdr   | range | date_acc      | date_acc | 8       | NULL | 3312740 |   100.00 | Using where |
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+

似乎只使用了前 8 个字节(密钥的日期部分)。然而,WHERE 子句用 AND 显式引用键的两个部分,因此理论上应该使用完整键。

我应该为 calldate 和 accountcode 创建单独的索引并让查询优化器合并它们吗?为什么不使用完整索引?

谢谢您的帮助!

4

2 回答 2

6

简短回答:如果您的密钥是 (accountcode, calldate) 而不是 (calldate, accountcode),您将能够更有效地使用索引。

理解该问题的最佳方法是将多列键视为不同列的串联。例如,如果第 1 列的值为 'A,B,C,D' 和第 2 列的值 'W,X,Y,Z' 你会在 'AW, BX, CY, DZ' 等上构建一个索引并把所有将它们放入 B 树中。

要进行范围查询,您会找到范围低端的第一个后继,并迭代直到超出范围上限。这意味着您只能有效地使用索引对键的后缀进行范围查询。

于 2011-01-04T23:01:47.073 回答
1

由于您正在寻找一系列日期(> '2010-12-01'),我看不出优化器如何使用完整索引。它可以做的最好的事情是扫描日期范围以查找匹配的帐户代码。现在,如果您正在寻找一个日期和一个帐户代码,那么我希望使用完整的索引。

于 2011-01-04T23:01:58.910 回答