2012-01-05 115 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. 具有相同的名称为已删除表采用优化的结构,并且具有创建视图与旧表相同的结构

对于第三方软件,表和视图之间没有区别。

您也可以在视图中添加触发器以使其可更新。