我正在寻找优化此查询的建议,该查询已经运行了一个多小时,表中有大约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 :(得分:1)
一般决策 - 将您的表拆分为两个或更多表 - 即 - 规范化数据结构。我认为可以引入另外两个表 - 适用于广告系列和主题
<强> BUT 强>
对于您当前的数据结构,您可以创建uniqueidentifier
或bigint
计算列作为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
值 - sql server可以在行中保存一点空间,因此 - 在IO中
答案 1 :(得分:0)
<强>触发强>
在插入/更新/删除数据时更新频率字段?随着时间的推移传播负载,并且唯一更新的记录是与更改的数据相关的记录。
的 TopicID 强>
有一个主题表,可能有也可能不只有id, name
。然后,您可以使用(并索引)TopicID。
由于您在GROUP BY和JOIN中都有TopicName,因此能够对此进行索引会产生大量性能差异。
LastModified或其他审计跟踪
记录(并包含在索引中)上次修改时间或其他一些审计跟踪。这样,您就可以将更新范围缩小到自上次批处理以来已插入/更新/删除记录的主题。
的归一化强>
将频率值保存在另一个表中,按“广告系列”,“类别”,“主题”键入。
目前,如果你的COUNT(*)产生100,你就会更新100条记录。规范化将意味着每组更新一次。
明显的注意事项?
仅仅因为您对基础数据进行了规范化或重构,您是否(当然?)无法将该表替换为“更好”设计结构的视图?
报告工具将视图视为表格。数据处理直接与重构表结构进行交互,以多更有效的方式进行。
分离数据报告注意事项和数据处理注意事项将使您成为更自由的人。
答案 2 :(得分:0)
如果您可以避免使用相关子查询来更新它,我认为它会提高性能。为什么不直接加入表并更新表。请参阅this链接
答案 3 :(得分:0)
前段时间我遇到过类似问题:第三方软件使用的表格对于某些数据操作来说太大了。我解决问题的诀窍是:
对于第三方软件,表和视图之间没有区别。
您还可以在视图上添加触发器以使其可更新。