请帮我处理这个查询(sql server 2008)
Posted
技术标签:
【中文标题】请帮我处理这个查询(sql server 2008)【英文标题】:Please help me with this query (sql server 2008) 【发布时间】:2011-01-06 09:08:05 【问题描述】:ALTER PROCEDURE ReadNews
@CategoryID INT,
@Culture TINYINT = NULL,
@StartDate DATETIME = NULL,
@EndDate DATETIME = NULL,
@Start BIGINT, -- for paging
@Count BIGINT -- for paging
AS
BEGIN
SET NOCOUNT ON;
--ItemType for news is 0
;WITH Paging AS
(
SELECT news.ID,
news.Title,
news.Description,
news.Date,
news.Url,
news.Vote,
news.ResourceTitle,
news.UserID,
ROW_NUMBER() OVER(ORDER BY news.rank DESC) AS RowNumber, TotalCount = COUNT(*) OVER()
FROM dbo.News news
JOIN ItemCategory itemCat ON itemCat.ItemID = news.ID
WHERE itemCat.ItemType = 0 -- news item
AND itemCat.CategoryID = @CategoryID
AND (
(@StartDate IS NULL OR news.Date >= @StartDate) AND
(@EndDate IS NULL OR news.Date <= @EndDate)
)
AND news.Culture = @Culture
and news.[status] = 1
)
SELECT * FROM Paging WHERE RowNumber >= @Start AND RowNumber <= (@Start + @Count - 1)
OPTION (OPTIMIZE FOR (@CategoryID UNKNOWN, @Culture UNKNOWN))
END
这是News
和ItemCategory
表的结构:
CREATE TABLE [dbo].[News](
[ID] [bigint] NOT NULL,
[Url] [varchar](300) NULL,
[Title] [nvarchar](300) NULL,
[Description] [nvarchar](3000) NULL,
[Date] [datetime] NULL,
[Rank] [smallint] NULL,
[Vote] [smallint] NULL,
[Culture] [tinyint] NULL,
[ResourceTitle] [nvarchar](200) NULL,
[Status] [tinyint] NULL
CONSTRAINT [PK_News] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE TABLE [ItemCategory](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[ItemID] [bigint] NOT NULL,
[ItemType] [tinyint] NOT NULL,
[CategoryID] [int] NOT NULL,
CONSTRAINT [PK_ItemCategory] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
此查询读取特定类别(体育、政治等)的新闻。
@Culture
参数指定新闻的语言,如 0(英文)、1(法文)等。
ItemCategory
表将新闻记录与一个或多个类别相关联。
ItemCategory
表中的ItemType
列指定了itemID
的类型。目前,我们只有ItemType
0 表示ItemID
引用News
表中的记录。
目前,我在ItemCategory
表上有以下索引:
CREATE NONCLUSTERED INDEX [IX_ItemCategory_ItemType_CategoryID__ItemID] ON [ItemCategory]
(
[ItemType] ASC,
[CategoryID] ASC
)
INCLUDE ( [ItemID])
以及新闻表的以下索引(由查询分析器建议):
CREATE NONCLUSTERED INDEX [_dta_index_News_8_1734000549__K1_K7_K13_K15] ON [dbo].[News]
(
[ID] ASC,
[Date] ASC,
[Culture] ASC,
[Status] ASC
)
使用这些索引,当我执行查询时,对于某些参数,查询在不到一秒的时间内执行,而对于其他参数(例如不同的 @Culture 或 @CategoryID)可能需要长达 2 分钟!我使用OPTIMIZE FOR (@CategoryID UNKNOWN, @Culture UNKNOWN)
来防止对@CategoryID
和@Culture
参数的参数嗅探,但似乎不适用于某些参数。
目前News
表中有大约 2,870,000 条记录,ItemCategory
表中有 4,740,000 条记录。
现在,我非常感谢有关如何优化此查询或其索引的任何建议。
更新: 执行计划:(在这张图中,ItemNetwork 就是我所说的 ItemCategory。它们是一样的)
【问题讨论】:
您能否发布查询计划的文本版本,虽然它很可能使用索引,但我们需要查看它是否是索引扫描等。 这里是执行计划的图片:img31.imageshack.us/img31/899/readnewsplan.jpg 在这张图片中,ItemNetwork 就是我所说的ItemCategory。它们是一样的。 如果你需要文字版,我也提供。 【参考方案1】:请尝试更改
FROM dbo.News news
JOIN ItemCategory itemCat ON itemCat.ItemID = news.ID
到
FROM dbo.News news
HASH JOIN ItemCategory itemCat ON itemCat.ItemID = news.ID
或
FROM dbo.News news
LOOP JOIN ItemCategory itemCat ON itemCat.ItemID = news.ID
我真的不知道你的数据中有什么,但是这些表的连接可能是一个瓶颈。
【讨论】:
【参考方案2】:我终于想出了以下索引,它们运行良好,存储过程在不到一秒的时间内执行。我刚刚从查询中删除了TotalCount = COUNT(*) OVER()
,我找不到任何好的索引。也许我编写了一个单独的存储过程来计算记录总数。我什至可能决定使用没有分页按钮的 Twitter 和 Facebook 中的“更多”按钮。
新闻表:
CREATE NONCLUSTERED INDEX [IX_News_Rank_Culture_Status_Date] ON [dbo].[News]
(
[Rank] DESC,
[Culture] ASC,
[Status] ASC,
[Date] ASC
)
对于 ItemNetwork 表:
CREATE NONCLUSTERED INDEX [IX_ItemNetwork_ItemID_NetworkID] ON ItemNetwork
(
[ItemID] ASC,
[NetworkID] ASC
)
我只是不知道 ItemNetwork 是否需要 ID 列上的聚集索引。我从不使用 ID 列从该表中检索记录。您认为在 (ItemID, NetworkID) 列上使用聚集索引更好吗?
【讨论】:
【参考方案3】:尝试对 ItemCategory 表使用 itemId、categoryId 和 News 表的非聚集索引以及 Rank、Culture 的非聚集索引。
【讨论】:
【参考方案4】:确实需要查看查询计划 - 需要注意的一点是您将 News 的聚集索引放在 News.ID 上,但它不是标识字段而是 ItemCategory 表的 FK,这会导致一些碎片随着时间的推移新闻表,所以它不太理想。
我怀疑根本问题是您的分页导致表扫描。
更新:
这些排序花费了计划中 68% 的查询执行时间,这是有道理的,其中一种排序至少必须支持您正在使用的基于 news.rank desc 的排名函数,但是您没有可以原生支持该排名的索引。
获取一个索引来支持这会很有趣,你可以在 news.rank 上尝试一个简单的 NC 索引,SQL 可能会选择加入索引并避免排序,但这需要一些实验。
【讨论】:
我暂时禁用了新闻表上 ID 列的身份特征。因此,将其视为身份列。我还用执行计划的图像更新了我的问题。请看一下。 img31.imageshack.us/img31/899/readnewsplan.jpg 在 news.rank desc 上添加 NC 索引没有任何区别。执行计划保持不变,我创建的索引没有被使用! 我确实说过让索引支持排序会很有趣 - 排名不能放在其他索引之一中,所以除非你说服优化器加入索引,否则它会很困难.【参考方案5】:您应该查看为新闻表中的文化字段以及项目类别表中的 itemid 和 categoryid 字段建立索引。您可能不需要所有这些索引 - 我会一次尝试一个,然后组合使用,直到您找到有效的方法。您现有的索引似乎对您的查询没有太大帮助。
【讨论】:
【参考方案6】:OPTION OPTIMIZE 子句不应该是内部 SQL 的一部分,而不是 CTE 上的 SELECT 的一部分吗?
【讨论】:
【参考方案7】:您是否看过一些可以帮助您解决此问题的内置 SQL 工具:
即从管理工作室菜单:
'查询'->'显示预计执行计划' '查询'->'包括实际执行计划' “工具”->“数据库引擎优化顾问”【讨论】:
是的,新闻表的索引已由 Tuning Advisor 建议。我也看到了实际的执行计划和正在使用的索引。以上是关于请帮我处理这个查询(sql server 2008)的主要内容,如果未能解决你的问题,请参考以下文章
请帮我写个SQL SERVER的语句,显示:姓名 语文 数学 英语 历史 格式不知道怎么写,请看补充: