Ale*_*rey 6 mysql clustered-index
我有一个大表,我必须从中选择大量的行.
该表存储呼叫详细记录(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 | | | |
Run Code Online (Sandbox Code Playgroud)
由于我的查询在某些日期查找客户调用,因此我将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
Run Code Online (Sandbox Code Playgroud)
但是,在执行以下查询时,EXPLAIN结果显示仅使用键的日期时间部分:
查询:
SELECT *
FROM cdr
WHERE calldate > '2010-12-01'
AND accountcode = 'xxxxxx';
Run Code Online (Sandbox Code Playgroud)
EXPLAIN结果:
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+
| 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 |
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+
Run Code Online (Sandbox Code Playgroud)
似乎只使用了前8个字节(密钥的日期部分).但是,WHERE子句使用AND显式引用键的两个部分,因此理论上应使用完整键.
我应该为calldate和accountcode创建单独的索引,让查询优化器合并它们吗?为什么没有使用完整索引?
谢谢您的帮助!
简短回答:如果您的密钥是(帐户代码,校准密码)而不是(calldate,accountcode),那么您可以更有效地使用索引.
理解该问题的最佳方法是将多列密钥视为不同列的串联.例如,如果第1列的值为'A,B,C,D',则第2列'W,X,Y,Z',您将在'AW,BX,CY,DZ'等上构建索引,并将所有值设置为那些进入B树.
要进行范围查询,您会找到范围低端的第一个后继,并迭代直到超出上限.这意味着您只能有效地使用索引对键的后缀执行范围查询.