サブセレクトを使用してMySQLクエリがハングするのはなぜですか?

StackOverflow https://stackoverflow.com/questions/1601935

  •  05-07-2019
  •  | 
  •  

質問

次のクエリがハングします:(個別に実行されるサブクエリは問題ありませんが)

説明テーブルを適切に表示する方法がわかりません。誰かが私に言ったら、それをきれいにします。

select
sum(grades.points)) as p,  
from assignments 
left join grades using (assignmentID) 
where gradeID IN 

(select grades.gradeID 
from assignments 
left join grades using (assignmentID) 
where ... grades.date <= '1255503600' AND grades.date >= '984902400' 
group by     assignmentID order by grades.date DESC);

問題は1年生のテーブルにあると思います...その数の行を持つALL型が原因のようです。すべてがインデックス化されています。

表を画像としてアップロードしました。フォーマットを正しく取得できませんでした: http://imgur.com/AjX34.png

コメンターは完全なwhere句が必要でした:

explain extended select count(assignments.assignmentID) as asscount, sum(TRIM(TRAILING '-' FROM grades.points)) as p, sum(assignments.points) as t 
from assignments left join grades using (assignmentID) 
where gradeID IN 
(select grades.gradeID from assignments left join grades using (assignmentID) left join as_types on as_types.ID = assignments.type 
where assignments.classID = '7815' 
and (assignments.type = 30170 ) 
and grades.contactID = 7141 
and grades.points REGEXP '^[-]?[0-9]+[-]?' 
and grades.points != '-' 
and grades.points != '' 
and (grades.pointsposs IS NULL or grades.pointsposs = '') 
and grades.date <= '1255503600' 
AND grades.date >= '984902400' 
group by assignmentID 
order by grades.date DESC);
役に立ちましたか?

解決

Real Database(つまり、MySQLを除く任意のデータベースを使用しますが、Postgresを例として使用します)を使用してこのクエリを実行するとします:

SELECT * FROM ta WHERE aid IN (SELECT subquery)

実際のデータベースはサブクエリを見て、その行数を推定します:

  • 行数が少ない場合(数百万未満など)

サブクエリを実行してから、IDのメモリ内ハッシュを作成します。これにより、IDも一意になります。これはIN()の機能です。

次に、taからプルされた行数がtaのごく一部である場合、適切なインデックスを使用して行をプルします。または、テーブルの大部分が選択されている場合、テーブル全体をスキャンし、ハッシュ内の各IDを検索します。これは非常に高速です。

  • ただし、サブクエリの行数が非常に多い場合

データベースはおそらくマージJOINとして書き換え、サブクエリにSort + Uniqueを追加します。

ただし、MySQLを使用しています。この場合、これは何も行いません(テーブルの各行に対してサブクエリを再実行します)ので、1000年かかります。申し訳ありません。

他のヒント

「INの耐え難い遅さ」を参照してください: http://www.artfulsoftware.com/infotree/queries.php#568

非常に面倒ですが、:(みんなのおかげで)

   SELECT * 
   FROM grades
   LEFT JOIN assignments ON grades.assignmentID = assignments.assignmentID
   RIGHT JOIN (

   SELECT g.gradeID
 FROM assignments a
 LEFT JOIN grades g
 USING ( assignmentID ) 
 WHERE a.classID =  '7815'
 AND (
 a.type =30170
 )
 AND g.contactID =7141
  g.points
 REGEXP  '^[-]?[0-9]+[-]?'
 AND g.points !=  '-'
 AND g.points !=  ''
 AND (
 g.pointsposs IS NULL 
 OR g.pointsposs =  ''
 )
 AND g.date <=  '1255503600'
 AND g.date >=  '984902400'
 GROUP BY assignmentID
 ORDER BY g.date DESC
 ) AS t1 ON t1.gradeID = grades.gradeID

サブクエリを個別に実行したときに正常に動作する場合は、次のように、INではなくJOINを使用してみてください:

select count(assignments.assignmentID) as asscount, sum(TRIM(TRAILING '-' FROM grades.points)) as p, sum(assignments.points) as t 
from assignments left join grades using (assignmentID) 
join
(select grades.gradeID from assignments left join grades using (assignmentID) left join as_types on as_types.ID = assignments.type 
where assignments.classID = '7815' 
and (assignments.type = 30170 ) 
and grades.contactID = 7141 
and grades.points REGEXP '^[-]?[0-9]+[-]?' 
and grades.points != '-' 
and grades.points != '' 
and (grades.pointsposs IS NULL or grades.pointsposs = '') 
and grades.date <= '1255503600' 
AND grades.date >= '984902400' 
group by assignmentID 
order by grades.date DESC) using (gradeID);

あなたの質問に答えるのに十分な情報が本当にありません。そして、奇妙なwhere句の真ん中に...を置きました。関係するテーブルの大きさおよびインデックスは何ですか?

in句に含まれる用語が多すぎると、パフォーマンスが大幅に低下することがわかります。 inの使用を正しい結合に置き換えます

初心者の場合、in句のテーブル as_types は使用されません。左に参加しても意味がないので、取り除いてください。

これにより、in句には、外部クエリからの割り当てと成績テーブルのみが残ります。変更の割り当てがどこにあるかは、明らかに外部クエリのwhere句に属します。すべてのwhere grades = whatever を成績への左結合のon句に移動する必要があります。

クエリを追跡するのは少し難しいですが、サブクエリはまったく必要ないと思われます。 クエリは基本的に次のように思われます:

SELECT FOO()
FROM assignments LEFT JOIN grades USING (assignmentID)  
WHERE gradeID IN 
(
SELECT grades.gradeID
FROM assignments LEFT JOIN grades USING (assignmentID)  
WHERE your_conditions = TRUE
);

しかし、あなたはサブクエリのwhere句で本当に凝ったことをしていません。 もっと似ていると思う

SELECT FOO()
FROM assignments LEFT JOIN grades USING (assignmentID)  
GROUP BY groupings
WHERE your_conditions_with_some_tweaks = TRUE;

同様に機能します。

ここで重要なロジックが欠落している場合は、コメントしてください。この投稿を編集/削除します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top