簡體   English   中英

SQL 查詢 - 需要提高性能

[英]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 分鍾:!! :(

所以,我基本上需要一種方法來讓我的第一次嘗試查詢更好。 我也想知道這么多的數據,這是我應該期待的最佳檢索速度嗎?

  1. 我運行sp_helpindex ProductHistory並發現索引如下:

    PK_ProductHistoryNew - 位於 PRIMARY-Id、版本上的集群的、唯一的主鍵

  2. 我將第一個查詢包裝在 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))
  • 您正在嘗試使用相關子查詢獲取 max(changeid) 但您也加入了 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM