まず、FORCE INDEX
を試してみましょう いずれかのef
を選択します またはfe
。タイミングが短すぎてどちらが速いかを明確に把握することはできませんが、 `EXPLAINは違いを示しています:
filetime
に範囲を強制する 最初。 (注:WHERE
での順序 影響はありません。)
mysql> EXPLAIN SELECT COUNT(*), AVG(fsize)
FROM files FORCE INDEX(fe)
WHERE ext = 'gif' AND filetime >= '2015-01-01'
AND filetime < '2015-01-01' + INTERVAL 1 MONTH;
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
| 1 | SIMPLE | files | range | fe | fe | 14 | NULL | 16684 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
低カーディナリティのext
を強制する 最初:
mysql> EXPLAIN SELECT COUNT(*), AVG(fsize)
FROM files FORCE INDEX(ef)
WHERE ext = 'gif' AND filetime >= '2015-01-01'
AND filetime < '2015-01-01' + INTERVAL 1 MONTH;
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| 1 | SIMPLE | files | range | ef | ef | 14 | NULL | 538 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
明らかに、rows
ef
と言います 優れている。しかし、オプティマイザートレースで確認しましょう。出力はかなりかさばります。面白い部分だけを紹介します。 FORCE
はありません 必要です。トレースには両方のオプションが表示され、より適切なものが選択されます。
...
"potential_range_indices": [
...
{
"index": "fe",
"usable": true,
"key_parts": [
"filetime",
"ext",
"did",
"filename"
]
},
{
"index": "ef",
"usable": true,
"key_parts": [
"ext",
"filetime",
"did",
"filename"
]
}
],
...
"analyzing_range_alternatives": {
"range_scan_alternatives": [
{
"index": "fe",
"ranges": [
"2015-01-01 00:00:00 <= filetime < 2015-02-01 00:00:00"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 16684,
"cost": 20022, <-- Here's the critical number
"chosen": true
},
{
"index": "ef",
"ranges": [
"gif <= ext <= gif AND 2015-01-01 00:00:00 <= filetime < 2015-02-01 00:00:00"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 538,
"cost": 646.61, <-- Here's the critical number
"chosen": true
}
],
...
"attached_conditions_computation": [
{
"access_type_changed": {
"table": "`files`",
"index": "ef",
"old_type": "ref",
"new_type": "range",
"cause": "uses_more_keyparts" <-- Also interesting
}
}
fe
を使用 (範囲列が最初)、範囲を使用できますが、ext='gif'
を探して16684行をスキャンすると推定されました。 。
ef
を使用 (低カーディナリティext
まず、インデックスの両方の列を使用して、BTreeでより効率的にドリルダウンできます。次に、推定538行が見つかりました。これらはすべて、クエリに役立ちます。これ以上のフィルタリングは必要ありません。
結論:
-
INDEX(filetime, ext)
最初の列のみを使用しました。 -
INDEX(ext, filetime)
両方の列を使用しました。 -
=
に含まれる列を配置します 最初のテスト インデックス内カーディナリティに関係なく 。 - クエリプランは最初の「範囲」列を超えることはありません。
- 「カーディナリティ」は複合インデックスとこのタイプのクエリには関係ありません 。
(「インデックス条件の使用」とは、ストレージエンジン(InnoDB)がフィルタリングに使用される列以外のインデックスの列を使用することを意味します。)