[英]SQL Query - Need to improve performance
我有一個數據加載場景,我創建動態 sql 查詢以在我們的服務中提取數據和緩存。 有 1 個包含所有產品數據的表:ProductHistory(47 列,200,000 條記錄 + 並將繼續增長)
我需要:通過使用最大id、最大版本和最大changeid獲取最新產品。
第一次嘗試:
SELECT distinct Product.* FROM ProductHistory product
WHERE product.version =
(SELECT max(version) from ProductHistory p2 where product.Id = p2.Id
and product.changeId =
(SELECT max(changeid) from ProductHistory p3 where p2.changeId = p3.changeId))
這花了超過 2.51 分鍾。
其他失敗的嘗試:
select distinct product.* from ProductHistory product
where CAST(CAST(id as nvarchar)+'0'+CAST(Version as nvarchar)+'0'+CAST(changeid as nvarchar) as decimal) =
(select MAX(CAST(CAST(id as nvarchar)+'0'+CAST(Version as nvarchar)+'0'+CAST(changeid as nvarchar) as decimal)) from ProductHistory p2
where product.Id = p2.Id)
它基本上使用與訂購日期時相同的原則,將按相關性排序的數字連接起來。
For example 11 Jun 2007 = 20070711
And in our case: Id = 4 , version = 127, changeid = 32 => 40127032
The zeros are there not to mix up the 3 different ids
但是這個需要 3.10 分鍾:!! :(
所以,我基本上需要一種方法來讓我的第一次嘗試查詢更好。 我也想知道這么多的數據,這是我應該期待的最佳檢索速度嗎?
我運行sp_helpindex ProductHistory並發現索引如下:
PK_ProductHistoryNew - 位於 PRIMARY-Id、版本上的集群的、唯一的主鍵
我將第一個查詢包裝在 SP 中,但仍然沒有變化。
那么,想知道我們可以通過哪些其他方式來提高此操作的性能?
謝謝, Mani ps:我只是在 SQL 管理工作室中運行這些查詢來查看時間。
從 Sql Server Management Studio 運行查詢並查看查詢計划以了解瓶頸在哪里。 任何你看到“表掃描”或“索引掃描”的地方都必須通過所有數據 go 找到它正在尋找的內容。 如果您創建可用於這些操作的適當索引,它應該會提高性能。
我看到的一些東西:
DISTINCT
是必要的嗎? 如果你做一個DISTINCT *
它不太可能有任何好處,但它會在檢查所有字段中的重復項時產生開銷。WHERE
子句中有兩個子選擇,而是JOIN
派生表。 這應該只處理一次。 我懷疑您的WHERE
子句正在處理多次。<-- -->
SELECT Product.*
FROM ProductHistory product
INNER JOIN ( SELECT P.Id,
MAX(p.version) as [MaxVer],
MAX(p.Changeid) as [MaxChange]
FROM Product p
GROUP BY p.ID) SubQ
ON SubQ.ID = product.ID
AND SubQ.MaxChange = Product.ChangeID
AND SubQ.MaxVer = Product.Version
為此,您還應該有一個關於Id, Version, ChangeID
的索引。
好吧,將所有內容都存儲在表中並不是正確的方法。 最好將最后一個版本存儲在一個表中,並使用另一個(具有相同結構)的歷史記錄(因為我猜你對當前產品比對舊產品更感興趣)。 概念問題將產生許多解決方法......
此外,不要使用 DISTINCT,因為它通常會隱藏查詢中的問題(通常,如果檢索到重復項,則意味着您可以更好地優化)。
現在,最好的部分:如何解決您的問題? principle giving something like this:我想你應該使用原則給出這樣的東西:
SELECT max(id), max(version), max(changeid)
FROM ProductHistory p
WHERE <filter if necessary for old products or anything else>
GROUP BY version, changeid
HAVING version = max(version)
AND changeid = max(changeid)
AND id = max(id)
但是,如果我查看您的 PK,我很驚訝,changeid 不相關,因為您應該只處理 id 和版本......
我不確定我的要求是否完全正確,因為我無法測試,但我想你可以做一些測試。
試試這個 CTE,它應該是最快的選擇,你甚至可能不需要索引來獲得極快的速度:
with mysuperfastcte as (
select product.*,
row_number() over (partition by id order by version desc) as versionorder,
row_number() over (partition by id order by changeid desc) as changeorder
from ProductHistory as product
)
select distinct product.*
from mysuperfastcte
where versionorder = 1
and changeorder = 1;
注意。 我認為您的代碼此時可能存在錯誤,因此請確認並仔細檢查您對我的代碼所期望的結果:
and product.changeId = (SELECT max(changeid) from ProductHistory p3 where p2.changeId = p3.changeId))
另外 - 顯然減少您返回的列數,然后在運行查詢之前運行以下命令並檢查消息 output:
設置統計 IO ON
尋找具有高邏輯讀取的表,並找出索引可以幫助您的地方。
提示:如果我的代碼適合您,那么根據您需要的列,您可以執行以下操作:
在 ProductHistory 上創建索引 ix1 (id, version desc) include (changeid, .... )。
我希望這有幫助!
我認為您需要在(Id, changeId, version)
上為此查詢建立索引。 請提供表定義、現在表上的索引以及查詢的查詢計划。
這有點時髦,但我想知道分區是否可行:
SELECT Id
FROM (
SELECT Id,
MAX(version) OVER (PARTITION BY changeId) max_version
FROM ProductHistory
) s
where version = s.max_version
我感覺隨着行數的增加,這個查詢會花費更長的時間,但值得一試:
SELECT * FROM
(
SELECT Col1, Col2, Col3,
ROW_NUMBER() OVER (PARTITION BY ProductHistory.Id ORDER BY Version DESC, ChangeID DESC) AS RowNumber
FROM ProductHistory
)
WHERE RowNumber = 1
一般來說,select max() 需要對整個表進行排序。 你做了兩次
SELECT TOP 1 要快得多,但您需要確保您的索引是正確的並且您有正確的 ORDER BY。 看看你能不能玩這個。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.