2010-01-18 3 views
4
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 таблиц:Пожалуйста, помогите мне с этим запросом (SQL Server 2008)

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), чтобы предотвратить параметр sniffing для параметров @CategoryID и @Culture, но, похоже, не работает для некоторых параметров.

В настоящее время насчитывается около 2,870,000 записей в таблице News и 4,740,000 в таблице ItemCategory.

Теперь я ценю любые советы по оптимизации этого запроса или его индексов.

обновления: План исполнения:
enter image description here
(в этом образе, ItemNetwork является то, что я говорил, как ItemCategory они одинаковы.)

+0

Можете ли вы опубликовать текстовую версию плана запроса, хотя он вполне может использовать индексы, нам нужно увидеть, если это сканирование индексов и т. Д. – Andrew

+0

вот изображение плана выполнения: http: //img31.imageshack .us/img31/899/readnewsplan.jpg на этом изображении, ItemNetwork - это то, что я назвал ItemCategory. они одинаковые. – Meysam

+0

Если вам нужна текстовая версия, я также предоставил ее. – Meysam

ответ

0

Вы взглянули на некоторых из встроенных инструментов SQL, чтобы помочь вы с этим:

Т.е. из меню студии управления:

  • 'Запрос' -> 'Дисплей Оценочное плана исполнения'
  • 'Query' -> 'Включить фактический план выполнения'
  • 'Инструменты' -> 'Database Engine Tuning Advisor '
+0

Да, индекс для таблицы новостей был рекомендован консультантом по настройке. Я также видел фактический план выполнения, и индексы используются. – Meysam

0

Не должен ли пункт OPTION OPTIMIZE быть частью внутреннего SQL, а не SELECT на CTE?

0

Вы должны посмотреть на индексирование поля культуры в таблице новостей, а также поля itemid и categoryid в таблице категорий товаров. Возможно, вам не нужны все эти индексы - я бы попробовал их по одному, а затем в комбинации, пока вы не найдете что-то, что работает. Ваши существующие индексы, похоже, не очень помогают вашему запросу.

0

Действительно нужно увидеть план запроса - одно примечание - вы помещаете кластерный индекс для новостей в новостях.ID, но это не поле идентификации, а FK для таблицы ItemCategory, это приведет к некоторой фрагментации в новостной таблице с течением времени, поэтому она будет менее идеальной.

Я подозреваю, что основная проблема заключается в том, что ваш пейджинг вызывает сканирование таблицы.

Обновлено:

Те Сортировать являются стоить вам 68% времени выполнения запроса от плана, и это имеет смысл, один из тех видов, по крайней мере, должна быть для поддержки функции ранжирования, который вы используете, который основан на news.rank desc, но у вас нет индекса, который мог бы поддержать этот рейтинг изначально.

Получение индекса в поддержку, что будет интересно, вы можете попробовать простой индекс NC на news.rank, SQL может выбрать объединение индексов и избежать сортировки, но это потребует некоторых экспериментов.

+0

Я временно отключил идентификационную характеристику столбца ID в таблице новостей. Итак, рассмотрите его как столбец идентичности. Я также обновил свой вопрос с изображением плана выполнения. пожалуйста, взгляните на это. http://img31.imageshack.us/img31/899/readnewsplan.jpg – Meysam

+0

добавление индекса NC на news.rank desc не имеет никакого значения. План выполнения остался прежним, и индекс, который я создал, не использовался! – Meysam

+0

Я действительно сказал, что было бы интересно получить индекс для поддержки сортировки - рейтинг не может быть помещен в один из других индексов, поэтому, если вы не убедите оптимизатора в том, что он сделает объединение индекса, он будет работать. – Andrew

0

Попробуйте использовать для таблицы ItemCategory некластеризованный индекс в itemId, categoryId и в таблице новостей также некластеризованный индекс Rank, Culture.

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)?

0

Пожалуйста, попробуйте изменить

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 

Я действительно не знаю, что в ваших данных, но соединение этих таблиц может быть узким местом.

Смежные вопросы