-1

次の自己結合クエリがあります。

SELECT A.id
FROM mytbl      AS A
LEFT JOIN mytbl AS B 
ON (A.lft BETWEEN B.lft AND B.rgt)

クエリは非常に遅く、実行計画を見ると、原因は JOIN でのフル テーブル スキャンにあるようです。テーブルには 500 行しかありません。これが問題ではないかと疑って、オプティマイザーの選択に違いが生じるかどうかを確認するために、100,000 行に増やしました。そうではありませんでした.100k行では、まだ完全なテーブルスキャンを実行していました.

私の次のステップは、次のクエリでインデックスを強制しようとすることでしたが、同じ状況が発生し、フル テーブル スキャンが発生します。

SELECT A.id
FROM categories_nested_set      AS A
LEFT JOIN categories_nested_set AS B 
FORCE INDEX (idx_lft, idx_rgt)
ON (A.lft BETWEEN B.lft AND B.rgt)

フル テーブル スキャン クエリの実行プラン:/

すべての列 (id、lft、rgt) は整数で、すべてインデックスが付けられます。

MySql がここでフル テーブル スキャンを実行するのはなぜですか?

全テーブル スキャンの代わりにインデックスを使用するようにクエリを変更するにはどうすればよいですか?

CREATE TABLE mytbl ( lft int(11) NOT NULL DEFAULT '0', 
 rgt int(11) DEFAULT NULL, 
 id int(11) DEFAULT NULL,
 category varchar(128) DEFAULT NULL,
  PRIMARY KEY (lft), 
  UNIQUE KEY id (id), 
  UNIQUE KEY rgt (rgt), 
  KEY idx_lft (lft), 
  KEY idx_rgt (rgt) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

ありがとう

4

2 に答える 2

2

多くのインデックスがあり、それらのいくつかは冗長です。それらのいくつかをクリアすることから始めましょう。インデックスが多すぎると、挿入と更新が遅くなります。

PRIMARY KEY (lft),
KEY idx_lft (lft), 

すでに lft で主キーが定義されているため、lft で別のインデックスを作成する必要はまったくありません。同様に、rgt の一意のインデックスでは、次に示す 2 番目のインデックスは必要ありません。

UNIQUE KEY rgt (rgt), 
KEY idx_rgt (rgt)

次に、クエリを見てみましょう。

SELECT A.id
FROM mytbl      AS A
LEFT JOIN mytbl AS B 
ON (A.lft BETWEEN B.lft AND B.rgt)

これが実際に遭遇するクエリである可能性は非常に低いです。500 行の場合、このクエリは 5000 行も生成する可能性がありますか? 一度に作成されたキー全体が本当に必要ですか? このクエリが遅い理由は、mysql が定数の範囲比較しか最適化できないためです。実際のクエリは次のようになる可能性が高くなります。

SELECT B.*
FROM mytbl      AS A
LEFT JOIN mytbl AS B 
ON (A.lft BETWEEN B.lft AND B.rgt) 
WHERE a.id = N;

特定の ID のノードを作成する場所。これはインデックスを使用し、非常に高速になります。あまり使用しないクエリを最適化するポイントは何ですか?

于 2016-07-21T06:30:30.207 に答える
-1

隣接リストとインデックスの組み合わせに関する情報がほとんどないため、次の SO の質問はソリューションにとって重要です。

MySQL & ネストされたセット: JOIN が遅い (インデックスを使用しない)

次のように、基本的な比較条件を追加すると、インデックスの使用がトリガーされるようです。

SELECT A.id
FROM mytbl      AS A
LEFT JOIN mytbl AS B ON (A.lft BETWEEN B.lft AND B.rgt)
-- THE FOLLOWING DUMMY CONDITIONS TRIGGER INDEX
WHERE A.lft > 0
AND B.lft > 0
AND B.rgt > 0

また、テーブル スキャンはもう必要ありません。

編集:クエリの修正バージョンと未修正バージョンの EXPLAIN 関数の比較: EXPLAIN 関数の結果、上が固定、下が固定ではない

于 2016-07-22T00:45:28.743 に答える