2010-04-24 37 views
1

我有一個100萬行的事務表。該表的字段名稱爲「代碼」以保留客戶的ID。大約有10,000個不同的客戶代碼。如何根據選定的一組值高效地從數據庫表中選擇行

我有一個GUI界面允許用戶從事務表中呈現報表。用戶可以選擇任意數量的客戶進行渲染。

我在使用操作員首先,它適用於少數客戶:

SELECT * FROM TRANS_TABLE WHERE CODE IN ('...', '...', '...') 

我很快就遇到問題,如果我選擇幾千個客戶。使用IN運算符有限制。

另一種方法是創建一個只有一個CODE字段的臨時表,並使用INSERT語句將選定的客戶代碼注入臨時表。然後我可以使用

SELECT A.* FROM TRANS_TABLE A INNER JOIN TEMP B ON (A.CODE=B.CODE) 

這適用於巨大的選擇不錯。但是,臨時表創建,INSERT注入和臨時表的刪除會導致性能開銷。

你知道更好的解決方案來處理這種情況的?

+1

這是一個典型的問題。第一個問題是,用戶會選擇這麼多的客戶嗎?什麼是常規用例? – shahkalpesh 2010-04-24 05:27:14

+0

常規用例是選擇1個客戶。但總有要求選擇任意客戶。我希望找到一個能夠滿足所有要求的銀彈解決方案,而不會做太多的事情......以適應每個需求。 – 2010-04-25 01:22:15

回答

1

您可以生成SQL如

SELECT * FROM TRANS_TABLE WHERE CODE IN (?,?,?,?,?,?,?,?,?,?,?) 

,直到你載入你需要的所有的ID在一個循環中重複使用它。好處是如果你只需要幾個ID,你的數據庫就不需要解析所有這些in-clause。如果很多ID是罕見的情況,那麼性能影響可能並不重要。如果您不擔心SQL解析緩存,那麼您可以將in子句的大小限制爲數據庫的實際限制,以便有時您不需要循環和其他時間。

0

當你必須以某種方式傳遞的ID,IN應該是最快的方法。

MSDN提到:

包括非常大量的IN子句中的值(成千上萬)會消耗資源並返回錯誤8623或8632.要解決此問題,存儲在中項目列表中。

如果您仍然可以使用IN並且查詢速度會變慢,您可以嘗試調整您的索引,例如爲查詢使用一些覆蓋索引。由於需要隨機磁盤I/O,因此通過聚簇索引查找隨機值可能會很慢。覆蓋索引可以減少這個問題。

如果你確實通過了IN的限制並且創建了一個臨時表,那麼只要你一次插入這些值(當然不是數千個查詢),我不希望創建表成爲一個主要問題)。選擇用最少的開銷的方法,喜歡這裏提到的那些之一:

http://blog.sqlauthority.com/2008/07/02/sql-server-2008-insert-multiple-records-using-one-insert-statement-use-of-row-constructor/

當然,如果在你的ID的一些靜態的模式,你可以通過選擇(如在SP或UDF)的。如果你得到那些成千上萬的ID你的數據庫本身,而不是將它們來回,你可以只存儲它們或使用子查詢...

+0

我的應用程序可以處理Firebird,MSSQL和MySQL等不同類型的數據庫。這些數據庫可能有不同的IN列表限制。 – 2010-04-25 01:24:20

0

也許你可以通過客戶代碼分開存儲過程逗號並使用這裏提到的分裂SQL函數:http://www.devx.com/tips/Tip/20009

然後聲明您插入的分裂值,並使用IN子句標表。

CREATE PROCEDURE prc_dosomething (
    @CustomerCodes varchar(MAX) 
) 
AS 

DECLARE @customercodetable table(code varchar(10)) -- or whatever length you require. 
SET @customercodetable = UTILfn_Split(@CustomerCodes) -- see the article above for the split function. 

-- do some magic stuff here :). 
2

如果使用SQL Server 2008中,要做到這一點,最快速的方法通常是用Table-Valued Parameter(TVP):

CREATE TYPE CodeTable AS TABLE 
(
    Code int NOT NULL PRIMARY KEY 
) 

DECLARE @Codes AS CodeTable 
INSERT @Codes (Code) VALUES (1) 
INSERT @Codes (Code) VALUES (2) 
INSERT @Codes (Code) VALUES (3) 
-- Snip codes 

SELECT t.* 
FROM @Codes c 
INNER JOIN Trans_Table t 
    ON t.Code = c.Code 

使用ADO.NET,您可以填充TVP directly from your code,所以你不需要生成所有這些INSERT語句 - 只需傳入DataTable,ADO.NET將處理剩下的部分。所以,你可以寫一個存儲過程是這樣的:

CREATE PROCEDURE GetTransactions 
    @Codes CodeTable READONLY 
AS 

SELECT t.* 
FROM @Codes c 
INNER JOIN Trans_Table t 
    ON t.Code = c.Code 

...,只是通過在@Codes值作爲參數。

相關問題