2010-03-31 49 views
0

我的SQL查詢有問題,需要花時間從數據庫中獲取所有記錄。任何身體幫助我。以下是數據庫示例:SQL查詢優化

order(order_id, order_nm) 
customer(customer_id, customer_nm) 
orderDetail(orderDetail_id, order_id, orderDate, customer_id, Comment) 

我想獲取最新的客戶和訂單詳細信息。
這裏是可能的解決方案:

我創建了GetLatestOrderByCustomer(CusID)函數來獲取最新的客戶信息。

CREATE FUNCTION [dbo].[GetLatestOrderByCustomer] 
(
    @cus_id int 
) 
RETURNS varchar(255) 
AS 
BEGIN 
    DECLARE @ResultVar varchar(255) 

    SELECT @ResultVar = tmp.comment 
    FROM 
    (
     SELECT TOP 1 orderDate, comment 
     FROM orderDetail 
     WHERE orderDetail.customer_id = @cust_id 
    ) tmp 


    -- Return the result of the function 
    RETURN @ResultVar 

END 

下面是我的SQL查詢

SELECT 
     customer.customer_id 
    , customer.customer_nm 
    , dbo.GetLatestOrderByCustomer(customer.customer_id) 
FROM Customer 
    LEFT JOIN orderDetail 
     ON orderDetail.customer_id = customer.customer_id 

這是需要時間來運行的功能。任何人都可以提出任何解決方案來改善它嗎?

+6

你需要停下來思考程序上。使用基於集合的連接而不是調用函數 – 2010-03-31 05:21:40

+0

當您爲您工作時,您應該選擇一個答案爲「正確」。你點擊你最喜歡的答案旁邊的大複選標記。 – 2010-03-31 13:11:18

回答

5

用途:

SELECT c.customer_id 
     , c.customer_nm 
     , y.comment 
    FROM CUSTOMER c 
LEFT JOIN (SELECT od.customer_id, 
        MAX(od.orderdate) AS max_date 
      FROM ORDERDETAIL od 
     GROUP BY od.customer_id) x ON x.customer_id = c.customer_id 
    JOIN (SELECT od.customer_id, 
        od.comment, 
        od.orderdate 
      FROM ORDERDETAIL od) y ON y.customer_id = c.customer_id 
            AND y.orderdate = x.max_date 

沒有必要的功能 - 使用派生表/內嵌視圖/子查詢。你的函數執行得不好的原因是因爲它對每個返回的行都執行。

+0

非常感謝。我在我的SQL查詢中應用了您的建議。然後,驚人!這完全降低了我的SQL查詢的成本。獲取我所有的數據需要幾秒鐘的時間。謝謝你的幫助。 – nvtthang 2010-03-31 09:44:58

+0

+1,太糟糕了,你可能永遠不會得到這個答案「選擇」爲正確的 – 2010-03-31 13:10:29

0

你有適當的指數嗎?

  • custoemr.customer_id,

  • orderDetail.customer_id

都應該被索引。應該可能是oder.OrderDate。如果沒有索引,你可以運行桌面掃描程序 - 而且你也不會說爲什麼你的查詢很慢,所以假設索引不好是我通常做的。

我覺得有趣的是,customer_id是訂單明細,而不是訂單 - 通常訂單被分配給一個客戶。

現在,從根本上錯了:

GetLatestOrderByCustomer沒有做到這一點的功能;)有一個TOP 1,但沒有 - ORDER BY。 SQL結果沒有確定的順序,除非你這麼說,所以返回的一個元素實際上是--RANDOM。

如果customer_id是一個越來越多的數字,則不需要具有功能。擺脫它,並將查詢部分合併到主SQL Query中 - 允許查詢優化器做更好的工作。

然後 - id字段不應該是字符串。嚴肅地說 - 你在那裏吹表演,時間很長。讓他們小巧,高效。 int,smallint。不要將它們用於「最終用戶」編碼(發票編號等) - 可以是具有唯一索引的獨立字符串字段。但連接字符串 - 特別是定義爲varchar(255)與int in join相比非常慢。

+0

謝謝,我很抱歉我的錯誤客戶必須在訂購表。我剛剛在我的案例中做了一個簡單的例子。我同意你應該既索引和更好的整數數據類型,並通過定義varchar(255)連接字符串。非常感謝您的建議。 – nvtthang 2010-03-31 10:01:51

0

根據數據庫的大小,使用OUTER APPLY可能會更快然後由@OMG小馬提供的解決方案:

SELECT c.customer_id 
, c.customer_nm 
, y.comment 
FROM customer c 
OUTER APPLY (
    SELECT TOP 1 o.comment 
    FROM orderdetail o 
    WHERE o.customer_id = c.customer_id 
    ORDER BY orderDate DESC 
) AS y 

查看查詢執行計劃如下。注意相對於批量查詢成本(俯視爲OUTER APPLY仰視是@OMG小馬的解決方案;在批處理中的其它查詢是插入到臨時表):

query execution plans