2011-01-04 9 views
6

大量の行を選択する必要がある大きなテーブルがあります。MySQLの複合インデックスが使用されていません

テーブルにはコール詳細レコード(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 

ただし、次のクエリを実行する場合、結果はキーのみ日時部分が使用されていることを示して説明します

クエリ:

最初の8バイト(キーの日付部分)が使用されていると思わ

+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+ 
| 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 | 
+----+-------------+-------+-------+---------------+----------+---------+------+---------+----------+-------------+ 

結果を説明しています。しかし、WHERE節はANDの両方の部分を明示的に参照するため、理論的には完全キーを使用する必要があります。

calldateとaccountcodeのインデックスを別々に作成し、クエリオプティマイザでそれらをマージさせる必要がありますか?なぜフルインデックスが使用されていないのですか?

ありがとうございました!

+0

そのクエリですべての行の100%がフィルタされているようです。それはフィルタリングされた列の値は何ですか?そのフィルタリングをしていないサンプルを提供できますか?私は以下の答えの1つに同意する、あなたは最初にフィルタを持っている必要がありますし、並べ替え。インデックスaccountcode、calldateはるかに良い結果が得られるはずです。 – TheJacobTaylor

答えて

6

短い答え:あなたのキーが(calldate、accountcode)ではなく(accountcode、calldate)だった場合、ここでより効果的にインデックスを使用できます。

問題を理解する最善の方法は、複数列のキーを異なる列の連結として考えることです。たとえば、列1に値 'A、B、C、D'、列2 'W、X、Y、Z'がある場合、AW、BX、CY、DZなどのインデックスを作成し、それらをBツリーに変換します。

範囲クエリを実行するには、範囲の下限の最初の後続を見つけて、上限を超えるまで繰り返します。これは、キーの接尾辞で範囲照会を行うためにのみ、索引を効果的に使用できることを意味します。

+0

マルチカラムキーで範囲クエリがどのように機能するかについての洞察をいただき、ありがとうございました。実際には、キーが他の方法で順序付けされている場合は、完全インデックスが使用されます。 –

+0

@Vinay、もし 'accountcode'が' calldate'よりも大きな基数を持っていれば、 – Pacerier

1

日付の範囲(> '2010-12-01')を探しているので、オプティマイザが完全なインデックスをどのように使用できるかはわかりません。それができるのは、一致するアカウントコードを探している日付の範囲をスキャンすることです。さて、正確に1つの日付とちょうど1つのアカウントコードを探していたら、完全なインデックスを使うと思います。

関連する問題