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!
The Benefits and Drawbacks of Using Indexes in MySQLIndexes consume disk space. Indexes degrade the performance of INSERT, UPDATE and DELETE queries – when data is updated, the index needs to be updated together with it. MySQL does not protect you from using multiple types of indexes at the same time.
Answer: Oracle SQL not using an index is a common complaint, and it's often because the optimizer thinks that a full-scan is cheaper than index access.
In case the query optimizer ignores the index, you can use the FORCE INDEX hint to instruct it to use the index instead. In this syntax, you put the FORCE INDEX clause after the FROM clause followed by a list of named indexes that the query optimizer must use.
Composite Index: MySQL lets you define indices on multiple columns, up to 16 columns. This index is called a Multi-column / Composite / Compound index. Let's say we have an index defined on 4 columns — col1 , col2 , col3 , col4 .
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With