6

大量の行を選択する必要がある大きなテーブルがあります。

このテーブルには、コール詳細レコード(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とアカウントコードを一緒にインデックス付けしました。

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の結果は、キーの日時部分のみが使用されていることを示しています。

クエリ:

SELECT * 
FROM cdr
WHERE calldate > '2010-12-01'
  AND accountcode = 'xxxxxx';

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

最初の8バイト(キーの日付部分)のみが使用されているようです。ただし、WHERE句はキーの両方の部分をANDで明示的に参照するため、理論的には完全なキーを使用する必要があります。

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

助けてくれてありがとう!

4

2 に答える 2

6

簡単な回答: キーが (calldate, accountcode) ではなく (accountcode, calldate) の場合、ここでインデックスをより効果的に使用できます。

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

範囲クエリを実行するには、範囲の下限の最初の後続を見つけ、範囲の上限を超えるまで繰り返します。これは、インデックスを効果的に使用して、キーのサフィックスに対して範囲クエリを実行できることを意味します。

于 2011-01-04T23:01:47.073 に答える
1

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

于 2011-01-04T23:01:58.910 に答える