web-dev-qa-db-ja.com

理論的にはインデックスを使用した高速クエリ、スロークエリログ内

これらのクエリの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)があります。なぜすべての行を検査するのですか?

3

コメントには多くの良い資料がありますが、私は早い段階で明白なことを見落としていたため、質問への答えはかなり簡単です。

私が見逃したのは、クエリでのORの繰り返し使用でした。これは、私が最初にANDと読み間違えたためです。これにより、大きな違いが生じます。あなたはこれを求めています:

WHERE relDst='24794' OR relSrc='24794'

MySQLのEXPLAINusing indexというフレーズを使用しているのは残念ですが、これは意味しないがインデックスで検索を実行しているためです。テーブルで必要なすべての列が単一のインデックスに含まれている場合は、実際に全テーブルスキャンと同じことを実行しても、Using indexを保持できます。実際、以下に示すように、それがまさにここで起こっていることです。

Using indexは、オプティマイザが実際のテーブル行からデータを読み取るのではなく、インデックスからデータを読み取ることを決定したことを意味します。ほとんどの場合、インデックスはテーブルの列の適切なサブセットであるため、SELECTのすべての列が単一のインデックスにある場合、処理されるデータのバイト数が少なくなります。 、CPU、I/O、メモリの観点からクエリのコストを削減できる可能性があります。したがって、これは適切な戦略ですが、インデックスがルックアップに使用されているという意味ではありません...必要な列データを読み取るための安価な場所であるというだけです。

ほとんどのクエリのtype列にはindexと表示されます。繰り返しますが、これはインデックスが使用されていることを意味するものではありません。これは実際にはtype = ALL-全テーブルスキャン-と同じですが、テーブルデータの代わりにインデックスツリーから読み取る...したがって、この値はtypeUsing indexと連動します。

ルックアップに使用されているインデックスは通常key出力のEXPLAIN列に表示されますが、type = indexref = NULLでは、それは何が起こっているのかではありません。

そのため、ほとんどのクエリで、オプティマイザはPRIMARYキーインデックス全体を最初から最後まで読み取り、1つの列ORに一致する値を持つ行を探します。

複数列のインデックスを使用してOR条件を解決することはできません。 AND条件、またはインデックスの最初の列で始まる列の連続サブセットを含む条件を解決するためにのみ使用できます。

2列のインデックスは、市区町村の電話帳によく似ています。姓、名の順にソートされます。通常、名前は太字で印刷され、住所は小さいまたは目立たない書体で印刷されます。

私は電話帳を使用して姓「Jones」OR名「John」の全員を見つけることはできませんが、それを非常に効果的かつ効率的に使用して、姓「Jones」の全員を見つけることができますAND名「ジョン」。 (したがって、以前に見逃したANDORの大きな違い)。これを非常に効果的に使用して、姓に関係なく姓が「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 ALLalwaysは舞台裏に一時テーブルを作成するため、filesortを回避することはできません...インデックスを持つことはできません...しかし、私は考えがちですが、上記に基づいて、これがクエリが「インデックスを使用していない」としてログに記録される理由ではありません。

最後に、ベンチマークを行うときは、クエリでSELECT SQL_NO_CACHEを使用して、毎回常に実際にクエリを実行していることを確認してください。クエリキャッシュから結果を取得します(システムで有効になっている場合)。

4