1

データベースに5つのテーブルがあります。メンバー、アイテム、コメント、投票、国。10個欲しいです。各項目のコメント数と投票数を取得したい。また、各アイテムを提出したメンバーとその出身国も欲しいです。

ここや他の場所に投稿した後、副選択を使用してカウントを取得し始めましたが、このクエリには10秒以上かかります!

SELECT `items_2`.*, 
   (SELECT COUNT(*) 
   FROM `comments` 
   WHERE (comments.Script = items_2.Id) 
   AND (comments.Active = 1)) 
  AS `Comments`, 
   (SELECT COUNT(votes.Member) 
   FROM `votes` 
   WHERE (votes.Script = items_2.Id) 
   AND (votes.Active = 1)) 
  AS `votes`, 
  `countrys`.`Name` AS `Country` 
FROM `items` AS `items_2` 
INNER JOIN `members` ON items_2.Member=members.Id AND members.Active = 1 
INNER JOIN `members` AS `members_2` ON items_2.Member=members.Id 
LEFT JOIN `countrys` ON countrys.Id = members.Country 
GROUP BY `items_2`.`Id` 
ORDER BY `Created` DESC 
LIMIT 10

私の質問は、これがこれを行う正しい方法であるかどうか、このステートメントを書くためのより良い方法があるかどうか、またはより良いまったく異なるアプローチがあるかどうかです。副選択を個別に実行して情報を集約する必要がありますか?

4

1 に答える 1

2

はい、サブクエリを集約結合として書き直すことができます(以下を参照)が、速度が遅いのは、クエリ自体ではなく、インデックスの欠落が原因であるとほぼ確信しています。EXPLAINクエリをほんの一瞬で実行するために追加できるインデックスを確認するために使用します。

記録のために、これは同等の集約結合です。

SELECT `items_2`.*,
  c.cnt AS `Comments`,
  v.cnt AS `votes`,
  `countrys`.`Name` AS `Country` 
FROM `items` AS `items_2` 
INNER JOIN `members` ON items_2.Member=members.Id AND members.Active = 1 
INNER JOIN `members` AS `members_2` ON items_2.Member=members.Id 
LEFT JOIN (
  SELECT Script, COUNT(*) AS cnt 
   FROM `comments` 
   WHERE Active = 1
   GROUP BY Script
) AS c
ON c.Script = items_2.Id 
LEFT JOIN ( 
  SELECT votes.Script, COUNT(*) AS cnt 
   FROM `votes` 
   WHERE Active = 1
   GROUP BY Script
) AS v
ON v.Script = items_2.Id 
LEFT JOIN `countrys` ON countrys.Id = members.Country 
GROUP BY `items_2`.`Id` 
ORDER BY `Created` DESC 
LIMIT 10

ただし、を使用してLIMIT 10いるため、参照用に上記で提供した同等の集約結合を使用するよりも、現在使用しているサブクエリを使用する方がほぼ確実にオフになります(またはオフになります)。

これは、悪いオプティマイザ(およびMySQLは恒星からはほど遠い)が、集約結合クエリの場合、 10個の値(あなたの)以外のすべてを無駄に捨てる前に、テーブルCOUNT(*)の完全な内容に対して集約作業を実行することになる可能性があるためです、一方、元のクエリの場合は、最初から、とテーブルに関する限り、厳密な最小値のみを調べます。CommentsVotesLIMITCommentsVotes

より正確には、元のクエリと同じようにサブクエリを使用すると、通常、インデックスルックアップを使用したネストされたループと呼ばれるものになります。集約結合を使用すると、通常、インデックススキャンまたはテーブルスキャンでのマージ結合またはハッシュ結合が発生します。前者(ネストされたループ)は、ループの数が少ない場合(この場合は10)、後者(マージおよびハッシュ結合)よりも効率的です。ただし、前者がループの数が多すぎる場合は、後者の方が効率的です(数万/数十万以上)、特にディスクが遅いがメモリが多いシステムでは。

于 2010-03-23T02:44:18.113 に答える