2010-12-28 8 views
1

次のようなクエリは、どのように実行するのに16時間以上かかることがありますか? (私たちは最適化の研究を中止しましたが、私たちの誰もDBの専門家ではありません)。セットベースの除外を行うのは非常に簡単なようですね。このクエリはサブクエリの合計よりもずっと長く実行されるのはなぜですか?

SELECT 
    field 
FROM 
    (subquery that returns 1173126 rows in 20 seconds) 
WHERE 
    field NOT IN (subquery that returns 3927646 rows in 69 seconds) 

この他に、あなたに十分な情報を提供して助けてくれるものはありますか?

(問題を引き起こしていることについてtricksyと具体的な何かがあります場合には、実際のクエリは、次の。)

SELECT blob FROM (
     SELECT a.line1 + '|' + substring(a.zip,1,5) as blob 
     FROM registrations r 
     JOIN customers c ON r.custId = c.Id 
     JOIN addresses a ON c.addressId = a.Id 
     WHERE r.purchaseDate > DATEADD(year,-1,getdate()) 
     GROUP BY a.line1 + '|' + substring(a.zip,1,5)) sq 
WHERE blob NOT IN (
     SELECT a.line1 + '|' + substring(a.zip,1,5) as blob 
     FROM registrations r 
     JOIN customers c ON r.custId = c.Id 
     JOIN addresses a ON c.addressId = a.Id 
     WHERE r.purchaseDate BETWEEN DATEADD(year,-5,getdate()) AND DATEADD(year,-1,getdate()) 
     GROUP BY a.line1 + '|' + substring(a.zip,1,5)) 

答えて

2

昨年の購入はあっても過去5年間以内の購入はないようです。

SELECT DISTINCT a.line1, SUBSTRING(a.zip, 1, 5) 
FROM addresses a 
WHERE id IN 
     (
     SELECT c.addressId 
     FROM customers c 
     JOIN registrations r 
     ON  r.custId = c.id 
     AND  r.purchaseDate > DATEADD(year, -1 ,getdate()) 
     ) 
     AND NOT EXISTS 
     (
     SELECT NULL 
     FROM customers c 
     JOIN registrations r 
     ON  r.custId = c.id 
     JOIN addresses ai 
     ON  ai.id = c.addressId 
     WHERE r.purchaseDate BETWEEN DATEADD(year,-5,getdate()) AND DATEADD(year,-1,getdate()) 
       AND ai.line1 = a.line1 
       AND SUBSTRING(ai.zip, 1, 5) = SUBSTRING(a.zip, 1, 5) 
     ) 

このクエリは、異なるIDとアドレスにline1, zipの重複を気に。あなたはそのような重複を持っていますか?

+0

ええ、私たちは "新しい"顧客を見つけており、IDの上に重複した1行目のZIPの組み合わせがあります。 – clweeks

+0

@clweeks:同じアドレスから3年前に購入した「id」が違うと、それは新しいものとしてカウントされません。 – Quassnoi

+0

正しい。世帯内の他の人が購入した可能性があります(またはデータのキーが間違っている)。新しい購入をした住所/世帯を探しています(5年以上前に購入した人が「新規」ですが、 。 – clweeks

2

あなたはこれを実現することはできませんが、NOT IN文がでIF文に変換されますクエリエンジン。したがって、あなたの例では、すべての行(3.9M)で巨大なIF文を構築しています。次に、それぞれのIF条件を評価して、その値が存在するかどうかを調べる必要があります。 16時間以上かかることは驚くことではありません。

これをEXISTSまたはおそらく結合に変換する方法を見つけようとする方がはるかに良いでしょう。

+0

これは、それぞれの「IF」条件を評価したり、それらをすべて構築したりすることはありません。これはセミジョインと呼ばれ、実行するためのさまざまなアルゴリズムがあります。 – Quassnoi

+0

私がここに投稿する前に、私は実行計画(実際に*使用方法はわかっていません)を掘り下げていました。私が持っていたクエリに "Left Anti Semi Join"しかし、私がしたいと思っているものすべてを読み上げる時間を見つけるのは大変です。 – clweeks

+0

@Quassnoi - 訂正ありがとうございます。私の理解は、IFステートメントが作成されたことでした。行の数が少ない場合は、これを行います。次に、より大きい行数の場合は準結合を行いますか? –

1

2番目のサブクエリは、最初のサブクエリの各行に対して1回実行されています。あなたはあなたのために実際のクエリ、最高のものを追加しました

意味する推定完了時間が前後になるだろう(1173126 * 69)= 80945394秒

およそ154年である

...

後表に索引を追加して2つの照会を最適化することです。追加するインデックスを正確に教えることはできませんが、テーブルの正しいインデックスを選択するための優れた記事がたくさんあります。

+0

これは動作しません。 – Quassnoi

関連する問題