问题
I have a large table from which I must select large amounts of rows.
The table stores call detail records (CDR's). Example:
+-------------+--------------+------+-----+---------------------+----------------+
| 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 | | | |
Since my queries look for a customers calls in certain dates, I indexed calldate and accountcode together in a clustered index like so:
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
However, when executing the following query, the EXPLAIN result shows that only the datetime portion of the key is being used:
Query:
SELECT *
FROM cdr
WHERE calldate > '2010-12-01'
AND accountcode = 'xxxxxx';
EXPLAIN result:
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+
| 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 |
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+
It seems only the first 8 bytes (the date portion of the key) is being used. However the WHERE clause explicitly references both parts of the key with an AND, so in theory the full key should be used.
Should I create separate indexes for calldate and accountcode and let the query optimizer merge them? Why is the full index not being used?
Thanks for the help!
回答1:
Short answer: You'd be able to use the index more effectively here if your key was (accountcode, calldate) instead of (calldate, accountcode).
The best way to understand the problem is by thinking of multi-column keys as being a concatenation of the different columns. As an example if column 1 had values 'A,B,C,D' and column 2 'W,X,Y,Z' you'd construct an index on 'A-W, B-X, C-Y, D-Z' etc. and put all of those into a B-tree.
To do a range query, you find the first successor of low end of the range, and iterate till you exceed the upper range. This means that you can only effectively use the index to do a range query on a suffix of the key.
回答2:
Since you're looking for a range of dates (> '2010-12-01'), I don't see how the optimizer could use the full index. The best it can do is scan the range of dates looking for the matching accountcode. Now, if you were looking for exactly one date and exactly one accountcode, then I'd expect the full index to be used.
来源:https://stackoverflow.com/questions/4599301/mysql-compound-index-not-being-used