私はこのクエリを持っています...これは非常にゆっくりと実行されます(ほぼ1分):
select distinct main.PrimeId
from PRIME main
join
(
select distinct p.PrimeId from PRIME p
left outer join ATTRGROUP a
on p.PrimeId = a.PrimeId or p.PrimeId = a.RelatedPrimeId
where a.PrimeId is not null and a.RelatedPrimeId is not null
) mem
on main.PrimeId = mem.PrimeId
PRIME テーブルには 18,000 行あり、PrimeId に PK があります。
ATTRGROUP テーブルには 24,000 行あり、PrimeId、col2、RelatedPrimeId、cols 4 ~ 7 に複合 PK があります。RelatedPrimeId には別のインデックスもあります。
クエリは最終的に 8.5k 行を返します。これは、ATTRGROUP テーブルの PrimeId または RelatedPrimeId と一致する PRIME テーブルの PrimeId の個別の値です。
ATTRGROUP の代わりに ATTRADDRESS を使用して、同じクエリを実行しました。ATTRADDRESS は、ATTRGROUP と同じキーとインデックスの構造を持っています。11,000 行しかありませんが、これは確かに小さいですが、その場合、クエリは約 1 秒で実行され、11,000 行が返されます。
だから私の質問はこれです:
構造が同一であるにもかかわらず、あるテーブルで別のテーブルよりもクエリが非常に遅くなるのはどうしてでしょうか。
これまでのところ、SQL 2005 と (同じデータベースを使用してアップグレードされた) SQL 2008 R2 でこれを試しました。私たち 2 人が別々に同じ結果を得て、同じバックアップを 2 台の異なるコンピューターに復元しました。
その他の詳細:
- 括弧内のビットは、遅いクエリでも 1 秒未満で実行されます
- 実行計画に手がかりがある可能性がありますが、私にはわかりません。これはその一部で、疑わしい 3 億 2000 万行の操作があります。
ただし、そのテーブルの実際の行数は 320M ではなく、24k を少し超えています。
OR ではなく UNION を使用するように、クエリの括弧内の部分をリファクタリングすると、次のようになります。
select distinct main.PrimeId
from PRIME main
join
(
select distinct p.PrimeId from PRIME p
left outer join ATTRGROUP a
on p.PrimeId = a.PrimeId
where a.PrimeId is not null and a.RelatedPrimeId is not null
UNION
select distinct p.PrimeId from PRIME p
left outer join ATTRGROUP a
on p.PrimeId = a.RelatedPrimeId
where a.PrimeId is not null and a.RelatedPrimeId is not null
) mem
on main.PrimeId = mem.PrimeId
...その後、遅いクエリは 1 秒未満かかります。
これに関する洞察をいただければ幸いです。さらに情報が必要な場合はお知らせください。質問を更新します。ありがとう!
ところで、この例では冗長な結合があることに気付きました。本番環境ではすべてが動的に生成され、括弧内のビットはさまざまな形式になるため、これを簡単に削除することはできません。
編集:
ATTRGROUP のインデックスを再構築しましたが、大きな違いはありません。
編集2:
したがって、一時テーブルを使用する場合:
select distinct p.PrimeId into #temp
from PRIME p
left outer join ATTRGROUP a
on p.PrimeId = a.PrimeId or p.PrimeId = a.RelatedPrimeId
where a.PrimeId is not null and a.RelatedPrimeId is not null
select distinct main.PrimeId
from Prime main join
#temp mem
on main.PrimeId = mem.PrimeId
...再び、元の OUTER JOIN に OR があっても、1 秒もかからずに実行されます。私はこのような一時テーブルが嫌いで、常に敗北を認めているように感じるので、使用するリファクタリングではありませんが、これだけの違いがあるのは興味深いと思いました。
編集3:
統計を更新しても違いはありません。
これまでのすべての提案に感謝します。