2012-01-05 103 views
3

我正在尋找建議來優化此查詢,該查詢已經在表中運行了一個多小時,約300,000行。我們正在使用一種報告工具,要求數據在被拉出時處於這種形狀,因此重新設計表格結構不是一種選擇。表看起來像這樣:優化更新查詢

CREATE TABLE [datatable](
    [RowID] [int] IDENTITY(1,1) NOT NULL, 
    [CampaignID] [int] NOT NULL, 
    [CampaignName] [nvarchar](255) NULL, 
    [Category] [nvarchar](255) NOT NULL, 
    [PostID] [int] NOT NULL, 
    [TopicName] [nvarchar](4000) NULL, 
    [TopicFrequency] [int] NULL 
) 

數據不斷添加到表中,所以我必須定期更新主題頻率。這是我目前的查詢:

UPDATE datatable 
SET  TopicFrequency = b.TopicFrequency 
FROM datatable INNER JOIN 
    (SELECT CampaignID, Category, TopicName, COUNT(DISTINCT PostID) AS TopicFrequency 
    FROM datatable GROUP BY CampaignID, Category, TopicName) AS b 
    ON datatable.CampaignID = b.CampaignID 
    AND datatable.Category = b.Category 
    AND datatable.TopicName = b.TopicName 

與主題名稱是nvarchar 4000我不能創建該字段上的索引。尋找想法。謝謝。

+0

索引怎麼樣? – zerkms 2012-01-05 01:00:10

+0

您是否檢查了查詢的執行計劃以找到瓶頸?組合CampaignID和Category列的索引可能會有所幫助。您可能需要在問題中添加標籤以指定您正在使用的數據庫,例如SQL服務器2008年。 – HABO 2012-01-05 04:00:07

回答

1

一般決定 - 將您的表分成兩個或多個表 - 即 - 規範化數據結構。我認爲這兩個表可以被引入 - 廣告活動和主題

爲您呈現的數據結構,你可以創建一個uniqueidentifierbigint計算列TopicName場的哈希值,指數去尋找新散列而不是字符串字段。我會爲您提供一個例子與bigint

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

CREATE FUNCTION [dbo].[HashString64SVF](@input NVARCHAR(4000)) 
RETURNS BIGINT 
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT 
AS 
BEGIN 
    RETURN 
     CAST(SUBSTRING(HASHBYTES('SHA1', UPPER(@Input)), 1, 8) AS BIGINT) 
    ^ CAST(SUBSTRING(HASHBYTES('SHA1', UPPER(@Input)), 9, 8) AS BIGINT) 
    ^ CAST(SUBSTRING(HASHBYTES('SHA1', UPPER(@Input)), 17, 4) AS BIGINT) 
END 
GO 
ALTER TABLE datatable ADD TopicNameHash AS dbo.HashString64SVF(TopicName) 
GO 
CREATE INDEX NewIndexName ON DataTable(TopicNameHash, CampaignID, Category) INCLUDE(PostId) 
GO 
UPDATE datatable 
SET  TopicFrequency = b.TopicFrequency 
FROM datatable 
JOIN 
    (SELECT CampaignID, Category, TopicNameHash, COUNT(DISTINCT PostID) AS TopicFrequency 
    FROM datatable GROUP BY CampaignID, Category, TopicNameHash) AS b 
    ON datatable.CampaignID = b.CampaignID 
    AND datatable.Category = b.Category 
    AND datatable.TopicNameHash = b.TopicNameHash 

創建於ROWID列主鍵

重新創建像這樣的表:

CREATE TABLE [datatable](
    [RowID] [int] IDENTITY(1,1) PRIMARY KEY, 
    [CampaignID] [int] NOT NULL, 
    [Category] [nvarchar](255) NOT NULL, 
    [PostID] [int] NOT NULL, 
    --uncomment if needed [TopicNameHash] AS dbo.HashString64SVF(TopicName), 
    [TopicFrequency] [int] NULL, 
    [CampaignName] [nvarchar](255) NULL, 
    [TopicName] [nvarchar](4000) NULL 
) 

主要的原因 - 如果你的可空變量列在列列表結束,有這些列中許多NULL值 - 在IO

0

觸發

更新頻率字段作爲數據被插入/更新/刪除?隨着時間的推移加載,唯一被更新的記錄是與更改的數據相關的記錄。


TopicID

有一個主題表,這可能會或可能不會有比只是id, name更多。然後您可以使用(並索引)TopicID。

由於您在GROUP BY和JOIN中都有TopicName,因此能夠對此進行索引將使大規模的性能出現差異。


上次更改時間或其他審覈跟蹤

記錄(幷包括在索引中)的最後修改時間,或一些其它的審計跟蹤。這將使您能夠將更新的範圍縮小到僅包含自上次批處理後插入/更新/刪除記錄的主題。


正常化

請另一個表的頻率值,通過運動,類別,主題關鍵字。

目前,如果您的COUNT(*)產量爲100,那麼您正在更新100條記錄。規範化將意味着每個組更新一次。


明顯的注意事項?

僅僅因爲你規範化或重構了底層數據,你是不是(當然?)阻止用視圖替換這個表到一個更好的設計結構?

報告工具讀取視圖,就好像它是表格一樣。數據處理直接與重構表結構交互,以更有效的方式進行交互。

分離數據報告注意事項和數據處理注意事項將使您成爲一個更自由的人。

0

如果你能 - SQL Server可以保存行一點點的空間,從而避免相關子查詢更新它,我認爲它會提高性能。你爲什麼不直接加入你的餐桌並更新餐桌。請參見this鏈接

0

前段時間我有類似的問題:第三方軟件使用的表對於某些數據操作來說太大了。招我做來解決問題是:

  1. 創建優化的表結構和從舊錶
  2. 複製數據刪除舊錶
  3. 具有相同的名稱爲已刪除表採用優化的結構,並且具有創建視圖與舊錶相同的結構

對於第三方軟件,表和視圖之間沒有區別。

您也可以在視圖中添加觸發器以使其可更新。