これらのクエリのEXPLAIN
結果を解釈するのに苦労しています。どちらもスロークエリログに記録されますが、実行時間は約0.0050ミリ秒で、最終結果セットは常に100行未満です。ここで何が問題になっていますか?私の2番目の「改善された」バージョンはより良いですか?
なにか提案を?
_ mysql> # Original
mysql> EXPLAIN SELECT SQL_NO_CACHE relSrc, relDst, 1 as relType, relTypeDesc, 0 as fracQty, '24794' as source FROM productsRelationships1
-> LEFT JOIN productsRelationshipsDesc on 1=relTypeID
-> WHERE relDst='24794' OR relSrc='24794'
-> UNION ALL
-> SELECT relSrc, relDst, 2 as relType, relTypeDesc, 0 as fracQty, '24794' as source FROM productsRelationships2
-> LEFT JOIN productsRelationshipsDesc on 2=relTypeID
-> WHERE relDst='24794' OR relSrc='24794'
-> UNION ALL
-> SELECT relSrc, relDst, 3 as relType, relTypeDesc, 0 as fracQty, '24794' as source FROM productsRelationships3
-> LEFT JOIN productsRelationshipsDesc on 3=relTypeID
-> WHERE relDst='24794' OR relSrc='24794'
-> UNION ALL
-> SELECT relSrc, relDst, 5 as relType, relTypeDesc, 0 as fracQty, '24794' as source FROM productsRelationships5
-> LEFT JOIN productsRelationshipsDesc on 5=relTypeID
-> WHERE relDst='24794' OR relSrc='24794'
-> UNION ALL
-> SELECT relSrc, relDst, 6 as relType, relTypeDesc, fracQty, '24794' as source FROM productsRelationships6
-> LEFT JOIN productsRelationshipsDesc on 6=relTypeID
-> WHERE relDst='24794' OR relSrc='24794'
-> UNION ALL
-> SELECT relSrc, relDst, 7 as relType, relTypeDesc, 0 as fracQty, '24794' as source FROM productsRelationships7
-> LEFT JOIN productsRelationshipsDesc on 7=relTypeID
-> WHERE relDst='24794' OR relSrc='24794'
-> ORDER BY relType, relSrc, RelDst;
+----+--------------+---------------------------+-------------+---------------------+---------------+---------+-------+-------+-----------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+---------------------------+-------------+---------------------+---------------+---------+-------+-------+-----------------------------------------+
| 1 | PRIMARY | productsRelationships1 | index | PRIMARY,src-1 | src-1 | 2 | NULL | 663 | Using where; Using index |
| 1 | PRIMARY | productsRelationshipsDesc | ref | relTypeID | relTypeID | 1 | const | 1 | Using index |
| 2 | UNION | productsRelationships2 | index | src-dst-2 | src-dst-2 | 4 | NULL | 13126 | Using where; Using index |
| 2 | UNION | productsRelationshipsDesc | ref | relTypeID | relTypeID | 1 | const | 1 | Using index |
| 3 | UNION | productsRelationships3 | index | PRIMARY | PRIMARY | 4 | NULL | 11459 | Using where; Using index |
| 3 | UNION | productsRelationshipsDesc | ref | relTypeID | relTypeID | 1 | const | 1 | Using index |
| 4 | UNION | productsRelationships5 | index | PRIMARY,src-5 | src-5 | 2 | NULL | 369 | Using where; Using index |
| 4 | UNION | productsRelationshipsDesc | ref | relTypeID | relTypeID | 1 | const | 1 | Using index |
| 5 | UNION | productsRelationships6 | index_merge | PRIMARY,src-6,dst-6 | dst-6,PRIMARY | 2,2 | NULL | 2 | Using union(dst-6,PRIMARY); Using where |
| 5 | UNION | productsRelationshipsDesc | ref | relTypeID | relTypeID | 1 | const | 1 | Using index |
| 6 | UNION | productsRelationships7 | index | PRIMARY,src-7 | src-7 | 2 | NULL | 1 | Using where; Using index |
| 6 | UNION | productsRelationshipsDesc | ref | relTypeID | relTypeID | 1 | const | 1 | Using index |
| NULL | UNION RESULT | <union1,2,3,4,5,6> | ALL | NULL | NULL | NULL | NULL | NULL | Using filesort |
+----+--------------+---------------------------+-------------+---------------------+---------------+---------+-------+-------+-----------------------------------------+
13 rows in set (0.00 sec)
mysql>
mysql>
mysql> # Improved?
mysql> EXPLAIN SELECT SQL_NO_CACHE relSrc, relDst, relType, fracQty, source, relTypeDesc FROM (
-> SELECT relSrc, relDst, 1 as relType, 0 as fracQty, '24794' as source FROM productsRelationships1
-> WHERE relDst='24794' OR relSrc='24794'
-> UNION ALL
-> SELECT relSrc, relDst, 2 as relType, 0 as fracQty, '24794' as source FROM productsRelationships2
-> WHERE relDst='24794' OR relSrc='24794'
-> UNION ALL
-> SELECT relSrc, relDst, 3 as relType, 0 as fracQty, '24794' as source FROM productsRelationships3
-> WHERE relDst='24794' OR relSrc='24794'
-> UNION ALL
-> SELECT relSrc, relDst, 5 as relType, 0 as fracQty, '24794' as source FROM productsRelationships5
-> WHERE relDst='24794' OR relSrc='24794'
-> UNION ALL
-> SELECT relSrc, relDst, 6 as relType, fracQty, '24794' as source FROM productsRelationships6
-> WHERE relDst='24794' OR relSrc='24794'
-> UNION ALL
-> SELECT relSrc, relDst, 7 as relType, 0 as fracQty, '24794' as source FROM productsRelationships7
-> WHERE relDst='24794' OR relSrc='24794'
-> ) AS rels
-> LEFT JOIN productsRelationshipsDesc ON relType=relTypeID
-> ORDER BY relType, relSrc, RelDst;
+----+--------------+---------------------------+-------------+---------------------+---------------+---------+--------------+-------+------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+---------------------------+-------------+---------------------+---------------+---------+--------------+-------+------------------------------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 38 | Using filesort |
| 1 | PRIMARY | productsRelationshipsDesc | ref | relTypeID | relTypeID | 1 | rels.relType | 1 | Using index |
| 2 | DERIVED | productsRelationships1 | index | PRIMARY,src-1 | src-1 | 2 | NULL | 663 | Using where; Using index |
| 3 | UNION | productsRelationships2 | index | src-dst-2 | src-dst-2 | 4 | NULL | 13126 | Using where; Using index |
| 4 | UNION | productsRelationships3 | index | PRIMARY | PRIMARY | 4 | NULL | 11459 | Using where; Using index |
| 5 | UNION | productsRelationships5 | index | PRIMARY,src-5 | src-5 | 2 | NULL | 369 | Using where; Using index |
| 6 | UNION | productsRelationships6 | index_merge | PRIMARY,src-6,dst-6 | dst-6,PRIMARY | 2,2 | NULL | 2 | Using union(dst-6,PRIMARY); Using where; Using index |
| 7 | UNION | productsRelationships7 | index | PRIMARY,src-7 | src-7 | 2 | NULL | 1 | Using where; Using index |
| NULL | UNION RESULT | <union2,3,4,5,6,7> | ALL | NULL | NULL | NULL | NULL | NULL | |
+----+--------------+---------------------------+-------------+---------------------+---------------+---------+--------------+-------+------------------------------------------------------+
9 rows in set (0.00 sec)
_
それらはテーブルの定義です
_ mysql> SHOW CREATE TABLE productsRelationships1\G
*************************** 1. row ***************************
Table: productsRelationships1
Create Table: CREATE TABLE `productsRelationships1` (
`relSrc` smallint(5) unsigned NOT NULL,
`relDst` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`relSrc`,`relDst`),
UNIQUE KEY `src-1` (`relSrc`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE productsRelationships2\G
*************************** 1. row ***************************
Table: productsRelationships2
Create Table: CREATE TABLE `productsRelationships2` (
`relSrc` smallint(5) unsigned NOT NULL,
`relDst` smallint(5) unsigned NOT NULL,
KEY `src-dst-2` (`relSrc`,`relDst`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE productsRelationships3\G
*************************** 1. row ***************************
Table: productsRelationships3
Create Table: CREATE TABLE `productsRelationships3` (
`relSrc` smallint(5) unsigned NOT NULL,
`relDst` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`relSrc`,`relDst`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE productsRelationships5\G
*************************** 1. row ***************************
Table: productsRelationships5
Create Table: CREATE TABLE `productsRelationships5` (
`relSrc` smallint(5) unsigned NOT NULL,
`relDst` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`relSrc`,`relDst`),
UNIQUE KEY `src-5` (`relSrc`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE productsRelationships6\G
*************************** 1. row ***************************
Table: productsRelationships6
Create Table: CREATE TABLE `productsRelationships6` (
`relSrc` smallint(5) unsigned NOT NULL,
`relType` tinyint(2) unsigned NOT NULL DEFAULT '6',
`fracQty` int(2) unsigned NOT NULL,
`relDst` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`relSrc`,`relDst`),
UNIQUE KEY `src-6` (`relSrc`),
UNIQUE KEY `dst-6` (`relDst`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE productsRelationships7\G
*************************** 1. row ***************************
Table: productsRelationships7
Create Table: CREATE TABLE `productsRelationships7` (
`relSrc` smallint(5) unsigned NOT NULL,
`relDst` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`relSrc`,`relDst`),
UNIQUE KEY `src-7` (`relSrc`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE productsRelationshipsDesc\G
*************************** 1. row ***************************
Table: productsRelationshipsDesc
Create Table: CREATE TABLE `productsRelationshipsDesc` (
`relTypeID` tinyint(2) unsigned NOT NULL AUTO_INCREMENT,
`relTypeDesc` varchar(100) NOT NULL,
UNIQUE KEY `relTypeID` (`relTypeID`,`relTypeDesc`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
_
そして、これはすべてのテーブルのデータ量です。
_ mysql> SELECT COUNT(1) FROM productsRelationships1\G
*************************** 1. row ***************************
COUNT(1): 663
1 row in set (0.00 sec)
mysql> SELECT COUNT(1) FROM productsRelationships2\G
*************************** 1. row ***************************
COUNT(1): 263
1 row in set (0.00 sec)
mysql> SELECT COUNT(1) FROM productsRelationships3\G
*************************** 1. row ***************************
COUNT(1): 8551
1 row in set (0.01 sec)
mysql> SELECT COUNT(1) FROM productsRelationships5\G
*************************** 1. row ***************************
COUNT(1): 369
1 row in set (0.00 sec)
mysql> SELECT COUNT(1) FROM productsRelationships6\G
*************************** 1. row ***************************
COUNT(1): 80
1 row in set (0.00 sec)
mysql> SELECT COUNT(1) FROM productsRelationships7\G
*************************** 1. row ***************************
COUNT(1): 0
1 row in set (0.00 sec)
mysql> SELECT COUNT(1) FROM productsRelationshipsDesc\G
*************************** 1. row ***************************
COUNT(1): 7
1 row in set (0.00 sec)
_
更新:EXPLAIN
によると、インデックスを使用しているように見えますが、スロークエリログにこれは_# Query_time: 0.005458 Lock_time: 0.000340 Rows_sent: 38 Rows_examined: 50579
_と表示され、これがORDER句を取り出したときです
これは高速なクエリかもしれませんが、システムのすべての単一操作で呼び出されます。
UPDATE2:わかりました、私はここで夢中になります
_# Query_time: 0.003527 Lock_time: 0.000164 Rows_sent: 38 Rows_examined: 8554
SET timestamp=1370017780;
SELECT SQL_NO_CACHE relSrc, relDst, 3 as relType, 0 as fracQty, '24794' as source
FROM productsRelationships3
WHERE relSrc='24794' OR relDst='24794';
_
これはどのようにして可能ですか? _productsRelationships3
_には構成インデックスPRIMARY KEY (relSrc,relDst)
があります。なぜすべての行を検査するのですか?
コメントには多くの良い資料がありますが、私は早い段階で明白なことを見落としていたため、質問への答えはかなり簡単です。
私が見逃したのは、クエリでのOR
の繰り返し使用でした。これは、私が最初にAND
と読み間違えたためです。これにより、大きな違いが生じます。あなたはこれを求めています:
WHERE relDst='24794' OR relSrc='24794'
MySQLのEXPLAIN
がusing index
というフレーズを使用しているのは残念ですが、これは意味しないがインデックスで検索を実行しているためです。テーブルで必要なすべての列が単一のインデックスに含まれている場合は、実際に全テーブルスキャンと同じことを実行しても、Using index
を保持できます。実際、以下に示すように、それがまさにここで起こっていることです。
Using index
は、オプティマイザが実際のテーブル行からデータを読み取るのではなく、インデックスからデータを読み取ることを決定したことを意味します。ほとんどの場合、インデックスはテーブルの列の適切なサブセットであるため、SELECT
のすべての列が単一のインデックスにある場合、処理されるデータのバイト数が少なくなります。 、CPU、I/O、メモリの観点からクエリのコストを削減できる可能性があります。したがって、これは適切な戦略ですが、インデックスがルックアップに使用されているという意味ではありません...必要な列データを読み取るための安価な場所であるというだけです。
ほとんどのクエリのtype
列にはindex
と表示されます。繰り返しますが、これはインデックスが使用されていることを意味するものではありません。これは実際にはtype
= ALL
-全テーブルスキャン-と同じですが、テーブルデータの代わりにインデックスツリーから読み取る...したがって、この値はtype
はUsing index
と連動します。
ルックアップに使用されているインデックスは通常がkey
出力のEXPLAIN
列に表示されますが、type
= index
とref
= NULL
では、それは何が起こっているのかではありません。
そのため、ほとんどのクエリで、オプティマイザはPRIMARY
キーインデックス全体を最初から最後まで読み取り、1つの列OR
に一致する値を持つ行を探します。
複数列のインデックスを使用してOR
条件を解決することはできません。 AND
条件、またはインデックスの最初の列で始まる列の連続サブセットを含む条件を解決するためにのみ使用できます。
2列のインデックスは、市区町村の電話帳によく似ています。姓、名の順にソートされます。通常、名前は太字で印刷され、住所は小さいまたは目立たない書体で印刷されます。
私は電話帳を使用して姓「Jones」OR
名「John」の全員を見つけることはできませんが、それを非常に効果的かつ効率的に使用して、姓「Jones」の全員を見つけることができますAND
名「ジョン」。 (したがって、以前に見逃したAND
とOR
の大きな違い)。これを非常に効果的に使用して、姓に関係なく姓が「Jones」であるすべての人を見つけることができますが、私がやろうとしていることは、姓に関係なく、「John」という名前の全員を見つけることだけではまったく役に立ちません。
または、たぶんそうではありません。最適ではありませんが、それでもある程度は役立ちます。その類推を続けますが、「John」という名前の全員を見つける必要がまだあると仮定すると、ディレクトリのすべての行を読み取る必要がありますが、太字でない印刷物(アドレス)を読み取る必要はありません。名については何も言わないでください。
したがって、インデックス内のデータの順序付けから利益を得られなくても、インデックスから直接読み取ることの値... Using index
は、オプティマイザが列を読み取る必要を満たすことができるカバーするインデックスを見つけたことを意味しますインデックスがルックアップまたは結合に使用されるかどうかに関係なく、データ。
1つのテーブルが例外として際立っています。
| 5 | UNION | productsRelationships6 | index_merge | PRIMARY,src-6,dst-6 | dst-6,PRIMARY | 2,2 | NULL | 2 | Using union(dst-6,PRIMARY); Using where |
ここでの違いは、両方の列にインデックスがあり、対象の列がインデックスの左端(この場合は唯一)の列であるということです。
UNIQUE KEY `src-6` (`relSrc`),
UNIQUE KEY `dst-6` (`relDst`)
オプティマイザはindex_merge
最適化を巧みに選択します。両方のインデックスで目的の値を検索し、識別された行をマージします。
すべてのテーブルが同等の配置になっている場合、スロークエリログで調べられた行の数がはるかに少なくなるはずです。クエリがスロークエリログから完全に削除される可能性があります。
これらのインデックスは必ずしも一意のインデックスである必要はありませんが、一意のインデックスは常に1つの値しか返さないため、データがそれをサポートしている場合は理想的ですが、これを各テーブルに追加することをお勧めします。
KEY dst_src (relDst,relSrc)
...あるいは単に...
KEY (relDst)
これで、主キーとこの新しいインデックスの2つのインデックスが作成されました(これも、データに適している場合はUNIQUE
に、そうでない場合はそうしたくない場合があります)...そのうちの1つrelSrc(主キー)でソートされ、もう1つはrelDst ...でソートされるので、オプティマイザmayは、このキーと主キーの結果をマージし、関係する行の数を大幅に減らすことを選択します。
UNION ALL
alwaysは舞台裏に一時テーブルを作成するため、filesortを回避することはできません...インデックスを持つことはできません...しかし、私は考えがちですが、上記に基づいて、これがクエリが「インデックスを使用していない」としてログに記録される理由ではありません。
最後に、ベンチマークを行うときは、クエリでSELECT SQL_NO_CACHE
を使用して、毎回常に実際にクエリを実行していることを確認してください。クエリキャッシュから結果を取得します(システムで有効になっている場合)。