1

MySQL で (私にとって) 奇妙な動作を見つけました。簡単なクエリがあります:

SELECT CONVERT( `text`.`old_text` 
USING utf8 ) AS stext
FROM  `text` 
WHERE  `text`.`old_id` IN 
(    
 SELECT  `revision`.`rev_text_id`
 FROM  `revision` 
 WHERE  `revision`.`rev_id`
 IN 
  (    
  SELECT `page_latest`
  FROM  `page` 
  WHERE `page_id` = 108
  )
)

実行すると、phpmyadmin は 77.0446 秒の実行時間を示します。
しかし、私は交換します

WHERE  `text`.`old_id` IN 

WHERE  `text`.`old_id` = 

実行時間は約 0.001 秒に短縮されます。このクエリの結果

 SELECT  `revision`.`rev_text_id`
 FROM  `revision` 
 WHERE  `revision`.`rev_id`
 IN 
  (    
  SELECT `page_latest`
  FROM  `page` 
  WHERE `page_id` = 108
  )    

+------------+
|rev_text_id |
+------------+
|6506        |
+------------+

誰かがこの動作を説明できますか?

4

3 に答える 3

2

INDEX次の列を追加してみてください。

ALTER TABLE `text` ADD INDEX idx_text (old_id);
ALTER TABLE `revision` ADD INDEX idx_revision (rev_text_id);

そして次のクエリを実行します

SELECT  DISTINCT CONVERT(a.`old_text` USING utf8 ) AS stext
FROM    `text` a
        INNER JOIN `revision` b
            ON a.`old_id` = b.`rev_text_id`
        INNER JOIN `page` c
            ON b.`rev_id` = c.`page_latest`
WHERE   c.`page_id` = 108

PS: 次のクエリも実行して、それぞれの結果を投稿できますか?

DESC `text`;
DESC `revision`;
DESC `page`;
于 2012-11-20T13:17:54.873 に答える
1

MySQLDB は内部クエリの各結果をループして、外部クエリの各レコードと比較しています。2 番目の内部クエリ。

   WHERE  `revision`.`rev_id`
   IN 
   ( SELECT `page_latest`
     FROM  `page` 
     WHERE `page_id` = 108

IN の代わりに必ず '=' を使用する必要があります。個別のレコードを選択しているため、毎回 1 つのレコードしか返されないことがわかっている場合、結果をループしても意味がありません。

于 2012-11-20T13:21:25.187 に答える
1

ここでクエリのパフォーマンスを向上させる主な方法は 2 つあります。

  • インデックスを追加します(Kuyaが言及したものなど)
  • 可能であればサブクエリを取り除く

インデックスの場合、一致するものを検索している列にインデックスを追加します: text.old_id、revision.rev_text_id & page.page_id

ALTER TABLE `text` ADD INDEX idx_text (old_id);
ALTER TABLE `revision` ADD INDEX idx_revision (rev_text_id);
ALTER TABLE `page` ADD INDEX idx_page (page_id);

あなたの次の問題は、ネストされたサブセレクトがクエリ実行計画にとって地獄であるということです。これは、 JOIN と Subqueryについて議論している良いスレッドです。これは、 mySQL から実行計画情報を取得する方法に関する記事です。

実行計画を最初に見ると混乱する可能性がありますが、クエリの最適化に関心を持たなければならない場合は、これが最良の友となります。

これは、結合のみを使用した同じクエリの例です (inner または left を使用して、ほぼ同じ結果を得ることができます)。私はあなたのテーブルやデータを持っていないので、シナックスの問題を許してください (あなたの環境でコードが逐語的に動作することを確認する方法はありませんが、良い出発点になるはずです)。

SELECT 
  CONVERT( `text`.`old_text` USING utf8 ) AS stext
  FROM  `text` 
  -- inner join only returns rows when it can find a 
  --    matching `revision`.`rev_text_id` row to `text`.`old_id`
  INNER JOIN `revision`  
  ON `text`.`old_id` = `revision`.`rev_text_id` 
  -- Inner Join only returns rows  when it can find a 
  --  matching `page_latest` row to `page_latest`
  INNER JOIN `page`
  ON `revision`.`rev_id` = `page`.`page_latest`
WHERE `page`.`page_id` = 108
于 2012-11-20T13:27:58.993 に答える