3

2つのテーブルtestaとtestbがあります。

CREATE TABLE `testa` (
  `id` INT(10) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

CREATE TABLE `testb` (
  `id` INT(10) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(50) DEFAULT NULL,
  `aid1` INT(10) DEFAULT NULL,
  `aid2` INT(10) DEFAULT NULL,
  `aid3` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

現在、testaテーブルのidがtablebのaid1、aid2、aid3の任意の列と一致するすべての行を取得するために、以下のクエリを実行しています。クエリは正確な結果を取得していますが、実行に最低30秒かかり、長すぎます。UNIONを使用してクエリを最適化しようとしましたが、失敗しました。

SELECT a.id, a.name, b.name, b.id 
FROM testb b 
INNER JOIN testa a ON b.aid1 = a.id OR b.aid2 = a.id OR b.aid3 = a.id ;

クエリを最適化して、合計実行時間が2〜3秒以内になるようにするにはどうすればよいですか?

前もって感謝します...

EXPLAINの結果:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  b   ALL idx_aid1,idx_aid2,idx_aid3  (NULL)  (NULL)  (NULL)  10940   
1   SIMPLE  a   ALL PRIMARY (NULL)  (NULL)  (NULL)  7512    Using where; Using join buffer
4

4 に答える 4

4

aid1、aid2、aid3 が NULL であることを許可しているため (そして、明らかに、説明によるとほとんどが NULL です)、結合条件は実質的にインデックス付けできません。

なんで?aid1、aid2、または aid3 のいずれかが NULL の場合、 SQL 式b.aid1 = a.id OR b.aid2 = a.id OR b.aid3 = a.id は NULL と評価されます。これが、MySQL プランナーがインデックスを使用して表示しない理由です。

解決策: aid1、aid2、aid3 に NULL を使用しないでください。代わりに、testa に存在しないことが保証されている特別な ID (たとえば 0) を作成します。次に、testb.aid[123] が NULL でないことを確認します (以前は NULL だった場所に 0 を割り当てます)。

編集:この問題に別のアプローチを追加します。

テーブルをもう 1 つ追加してスキーマを変更する余裕がある場合は、この問題を解決することもできます。この新しいテーブルには、テーブル testb に現在保存されている援助のリストが含まれ、testb には、新しいテーブルにリンクする ID が 1 つだけ含まれます。これは、この回答で説明されている内容と似ているはずです。これに対する追加の利点は、(現在のように 3 つだけでなく) 任意の数の援助を許可できることです。

于 2012-11-23T08:05:37.760 に答える
1

他の人が提案した索引付けに加えて、ANALYZEテーブルの統計が最新になるようにテーブルを確認してください。統計が実際にテーブルにあるものと大きく異なる場合、クエリプランナーは悪い選択をします。

于 2012-11-23T06:09:23.917 に答える
0

INの代わりにと参加しようとしましたORか?

SELECT a.id, a.name, b.name, b.id FROM testb b INNER JOIN testa a ON a.id IN (b.aid1, b.aid2, b.aid3) ;

于 2012-11-23T08:12:30.417 に答える
0

フルテーブル スキャンを避けるために、次の列にインデックスを付ける必要があります

  `aid1` INT(10) DEFAULT NULL,
  `aid2` INT(10) DEFAULT NULL,
  `aid3` INT(10) DEFAULT NULL,

テーブルを変更したい場合

ALTER TABLE testb ADD INDEX (aid1);
ALTER TABLE testb ADD INDEX (aid2);
ALTER TABLE testb ADD INDEX (aid3);
于 2012-11-22T13:23:15.760 に答える