2017-08-24 57 views
2

我有我們所有訂單的表。訂單鏈接到一個人。每個人都被附屬於一家公司。現在我需要一份在某個日期之前從未下單過的所有公司名單。查詢工作正常,但速度很慢。更好的tsql查詢來找出誰是新客戶(或不存在的替代品)

這是我的T-SQL查詢:

SELECT 
    DISTINCT p1.company_id 
FROM 
    order o 
    JOIN person p1 ON (o.person_id = p1.id AND p1.company_id IS NOT NULL) 
WHERE 
    o.orderDate > '2017-01-01' 
AND 
    o.orderDate < '2017-09-01' 
AND NOT EXISTS (SELECT 
        p2.company_id 
       FROM 
        order o2 
        JOIN person p2 ON (o2.person_id = p2.id AND p2.company_id = p1.company_id) 
       WHERE 
        o2.orderDate < '2017-01-01') 

我已經改變了它從NOT IN的NOT EXISTS。因爲這是大多數人在這裏推薦的。沒有太大的幫助。一個更好的索引改善了這種情況,但查詢仍然很慢。我認爲這是因爲每個訂單都必須執行子查詢。

這是執行計劃: https://www.brentozar.com/pastetheplan/?id=SyAlAU3db
爲了簡單的原因,我刪除了我上面的例子)幾WHERE子句

查詢Azure上的SQL(和SQL Server Express 12發展)

運行

任何人有更好的想法如何解決這個問題?

+2

問題尋求幫助的性能應包括DDL,DML與測試data..if您的測試數據以及所涉及的表很大,嘗試了腳本架構和表的統計信息('右鍵單擊數據庫 - >生成腳本 - >選擇特定數據庫對象 - >在下一個屏幕選擇高級並選擇腳本統計)'並粘貼它的問題。有了這個信息任何一個repro同樣的問題你正在面對。否則,它很難回答你的問題.Pasting服務器版本也有幫助 – TheGameiswar

+1

你能告訴我們當前的執行計劃她嗎e:https://www.brentozar.com/pastetheplan/ –

+0

@Rammy一個更簡單的命中你。你有沒有嘗試EXCEPT聲明?有兩個類似的子集,在這裏你去。 此外,如果前面的註釋沒有意義,請分析1)索引2)列類型的執行計劃。 – hastrb

回答

1

如果你有共享的執行計劃,這將有助於性能分析。

我做了查詢的一些變化如下,如果提高您可以嘗試它

SELECT p1.company_id 
FROM order o 
INNER JOIN person p1 
    ON (o.person_id = p1.id AND p1.company_id IS NOT NULL) 
GROUP BY p1.company_id 
HAVING SUM(CASE WHEN (o.orderDate > '2017-01-01' AND o.orderDate < '2017-09-01') THEN 1 ELSE 0 END) > 0 
     AND 
     SUM(CASE WHEN orderDate < '2017-01-01' THEN 1 ELSE 0 END) = 0 
+0

第二次執行(與12s相比)。天才!非常感謝。 – Remy

0

我想這會做到這一點(哎呀錯過了還沒有訂購)

;With FirstOrders 
as 
(
    Select p1.company_id 
    ,  MIN(o.orderDate) as FirstCompanyOrder 
    From Orders o 
    Join Person P1 on o.person_id = p1.id 
    Group by P1.Company_id 
    Having MIN(o.OrderDate) < '2017-01-01' 
) 

Select distinct o.company_id 
From  Orders  o 
Left join FirstOrders FO on o.Company_id = FO.ComapnyId 
where FO.company_id is null 
1

什麼是這一個。希望我能正確理解任務。

(
    SELECT p1.company_id 
    FROM order o 
    JOIN person p1 
    ON o.person_id = p1.id 
    WHERE p1.company_id IS NOT NULL 
    AND o.orderDate > '2017-01-01' 
    AND o.orderDate < '2017-09-01' 
) 
EXCEPT 
(
    SELECT p2.company_id 
    FROM order o2 
    JOIN person p2 
    ON o2.person_id = p2.id 
    WHERE p2.company_id IS NOT NULL 
    AND o2.orderDate < '2017-01-01' 
) 
+0

只需要有所區別。 – cloudsafe

+0

@cloudsafe它不需要冗餘'DISTINCT'。這將是獨一無二的重複。 – hastrb

+0

也許我是誤解,但如果同一個人有很多訂單呢? – cloudsafe

0

可能,這將幫助你:

WITH cte AS 
(
    SELECT o.person_id, MIN(o.orderDate) minOrderDate 
     FROM order o 
     GROUP BY o.person_id 
) 
SELECT DISTINCT p1.company_id 
    FROM person p1 
    JOIN cte ON cte.person_id = p1.id 
    WHERE p1.company_id IS NOT NULL AND cte.minOrderDate > '2017-01-01' AND cte.minOrderDate < '2017-09-01';