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
表将新闻记录与一个或多个类别相关联。
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条记录。
现在,我非常感谢有关如何优化此查询或其索引的任何建议。
更新:
执行计划:
(在此图中,ItemNetwork就是我所说的ItemCategory。它们是相同的)
答案 0 :(得分:0)
您是否看过一些内置的SQL工具来帮助您:
即。来自管理工作室菜单:
答案 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
我真的不知道你的数据是什么,但加入这些表可能是一个瓶颈。