请帮我处理这个查询(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  

这是NewsItemCategory表的结构:

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)的主要内容,如果未能解决你的问题,请参考以下文章

如何找到 MS SQL Server 2008 的端口?

请帮我写个SQL SERVER的语句,显示:姓名 语文 数学 英语 历史 格式不知道怎么写,请看补充:

sql server 2000/2008 查询优化

编写 SQL Server 查询

为啥在eclipse中执行 sql server 的查询语句总是提示语法错误,请大家帮我看看。

如何在SQL Server 2008R2中查找未使用的列