请帮我解决这个问题(sql server 2008)

时间:2010-01-18 13:44:04

标签: sql-server performance indexing query-optimization

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表将新闻记录与一个或多个类别相关联。 ItemType表中的ItemCategory列指定了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条记录。

现在,我非常感谢有关如何优化此查询或其索引的任何建议。

更新: 执行计划:
enter image description here
(在此图中,ItemNetwork就是我所说的ItemCategory。它们是相同的)

7 个答案:

答案 0 :(得分:0)

您是否看过一些内置的SQL工具来帮助您:

即。来自管理工作室菜单:

  • '查询' - &gt;'显示估算的执行计划'
  • '查询' - &gt;'包含实际执行计划'
  • '工具' - &gt;'数据库引擎优化顾问'

答案 1 :(得分:0)

OPTION OPTIMIZE子句不应该是内部SQL的一部分,而不是CTE上的SELECT吗?

答案 2 :(得分:0)

您应该查看新闻表中的文化字段索引,以及项目类别表中的itemid和categoryid字段。您可能不需要所有这些索引 - 我会一次尝试一个,然后组合,直到找到有效的方法。您现有的索引似乎对您的查询没有多大帮助。

答案 3 :(得分:0)

真的需要查看查询计划 - 有一点需要注意的是你把Newss的聚集索引放在News.ID上,但它不是一个身份字段,而是ItemCategory表的FK,这会导致一些碎片随着时间的推移新闻表,所以它不太理想。

我怀疑潜在的问题是你的分页导致表扫描。

更新:

那些Sort会使你从计划中花费68%的查询执行时间,这是有道理的,其中一种至少必须支持你正在使用的基于news.rank desc的排名函数,但是你没有可以原生支持该排名的索引。

获取一个有趣的索引,你可以先在news.rank上尝试一个简单的NC索引,SQL可以选择连接索引并避免排序,但需要进行一些实验。

答案 4 :(得分:0)

尝试在itemId,categoryId和News表上使用ItemCategory表非聚集索引,也可以在Rank,Culture上使用非聚集索引。

答案 5 :(得分:0)

我终于提出了以下索引,这些索引工作得很好,存储过程在不到一秒的时间内执行。我刚刚从查询中删除了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)列上有一个聚簇索引会更好吗?

答案 6 :(得分:0)

请尝试更改

select count(distinct a.ST_NUM) 
          from table2 b, 
               table1 a,
               table 3 c
               where 
         b.VEND_CD in ($vendorCD1)
      and b.ITM_CD_1=($ITMCD)
      and b.area_num=($area)
      and b.area_num= a.area_num
      and b.itm_cd_2 = a.itm_cd_2
      and a.week_end =c.week_end 
      and c.week_end between ($startdate)  and  ($enddate)

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

我真的不知道你的数据是什么,但加入这些表可能是一个瓶颈。