Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
未使用MySQL复合索引_Mysql_Clustered Index - Fatal编程技术网

未使用MySQL复合索引

未使用MySQL复合索引,mysql,clustered-index,Mysql,Clustered Index,我有一个很大的表,我必须从中选择大量的行 该表存储呼叫详细记录(CDR)。例如: +-------------+--------------+------+-----+---------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+--------------+------+-----+

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

该表存储呼叫详细记录(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结果显示只使用了键的datetime部分:

查询:

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 |
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+
解释结果:

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创建单独的索引,并让查询优化器合并它们?为什么不使用完整索引


谢谢你的帮助

简短回答:如果您的键是(accountcode,calldate)而不是(calldate,accountcode),那么您可以更有效地使用索引

理解此问题的最佳方法是将多列键视为不同列的串联。例如,如果第1列的值为“A、B、C、D”,第2列的值为“W、X、Y、Z”,则应在“A-W、B-X、C-Y、D-Z”等上构造索引,并将所有这些索引放入B-树中


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

因为您正在查找日期范围(>'2010-12-01'),我看不出优化器如何使用完整索引。它所能做的最好的事情就是扫描日期范围,寻找匹配的accountcode。现在,如果您只查找一个日期和一个accountcode,那么我希望使用完整的索引。

它看起来像是用该查询过滤了所有行的100%。这不是筛选列的值吗?你能提供一个没有过滤的例子吗?我同意下面的一个答案,你应该先用过滤器,然后再排序。索引帐户代码,calldate。您应该会得到更好的结果。感谢您对范围查询如何在多列键上工作的深入了解,该解释非常有价值!实际上,如果键顺序相反,则使用完整索引。@Vinay,如果
accountcode
的基数大于
calldate
,则会提供完整索引。