Почему этот запрос быстрее без индекса? - PullRequest
5 голосов
/ 29 ноября 2010

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

У меня следующая структура таблицы:

CREATE TABLE [dbo].[Calls](
    [CallID] [varchar](8) NOT NULL PRIMARY KEY,
    [RecvdDate] [varchar](10) NOT NULL,
    [yr] [int] NOT NULL,
    [Mnth] [int] NOT NULL,
    [CallStatus] [varchar](50) NOT NULL,
    [Category] [varchar](100) NOT NULL,
    [QCall] [varchar](15) NOT NULL,
    [KOUNT] [int] NOT NULL)

В этой таблице около 220 тыс. Записей. Мне нужно вернуть все записи, у которых дата больше определенной даты. В этом случае 01.12.2009. Этот запрос вернет около 66 тыс. Записей, и его выполнение займет около 4 секунд. Из прошлых систем, над которыми я работал, это кажется высоким. Особенно учитывая, как мало записей в таблице. Поэтому я хотел бы сократить это время.

Так что мне интересно, что было бы хорошим способом снизить это? Я попытался добавить столбец даты в таблицу и преобразовать строку даты в столбец фактической даты. Затем я добавил индекс в этот столбец даты, но время осталось прежним. Учитывая, что записей не так много, я могу видеть, как сканирование таблицы может быть быстрым, но я думаю, что индекс может сократить это время.

Я также подумал о том, чтобы просто запросить столбцы месяца и года. Но я еще не пробовал. И хотел бы оставить его вне столбца даты, если это возможно. Но если нет, я могу это изменить.

Любая помощь приветствуется.

РЕДАКТИРОВАТЬ: Вот запрос, который я пытаюсь выполнить и проверить скорость таблицы. Я обычно выставляю столбцы, но для простоты я использовал *:

SELECT *
FROM _FirstSlaLevel_Tickets_New
WHERE TicketRecvdDateTime >= '12/01/2009'

РЕДАКТИРОВАТЬ 2: Итак, я упомянул, что я пытался создать таблицу со столбцом даты, которая содержала бы данные recvddate, но в качестве даты, а не varchar. Это то, что столбец TicketRecvdDateTime в запросе выше. Исходный запрос, который я выполняю к этой таблице:

SELECT *
FROM Calls
WHERE CAST(RecvdDate AS DATE) >= '12/01/2009'

Ответы [ 5 ]

4 голосов
/ 29 ноября 2010

SELECT * обычно будет давать низкую производительность.

Либо индекс будет игнорироваться, либо вы закончите поиск ключа / закладки в кластерном индексе.Неважно: оба могут работать плохо.

Например, если у вас есть этот запрос и индекс для TicketRecvdDateTime INCLUDEd CallStatus, то он, скорее всего, будет работать так, как ожидалось.Это будет покрытие

SELECT CallStatus
FROM _FirstSlaLevel_Tickets_New
WHERE TicketRecvdDateTime >= '12/01/2009'

Это в дополнение к ответу Рэнди Миндера: поиск по ключу / закладке может быть достаточно дешевым для нескольких строк, но не для большой частиданные таблицы.

4 голосов
/ 29 ноября 2010

Возможно, вы столкнулись с тем, что называется переломным моментом в SQL Server.Даже если у вас есть соответствующий индекс для столбца, SQL Server может в любом случае принять решение о сканировании таблицы, если ожидаемое количество возвращаемых строк превышает некоторый порог («переломный момент»).кажется вероятным, так как ваша очередь составляет 1/4 от числа строк в базе данных.Вот хорошая статья, которая объясняет это: http://www.sqlskills.com/BLOGS/KIMBERLY/category/The-Tipping-Point.aspx

3 голосов
/ 29 ноября 2010

Ваш запрос быстрее без индекса (или, точнее, с той же скоростью без индекса), потому что индекс RecvdDate будет всегда игнорироваться в выражение как CAST(RecvdDate AS DATE) >= '12/01/2009'. Это выражение, не поддерживающее SARG, так как требует преобразования столбца с помощью функции. Чтобы это событие индекса считалось , вы должны выразить критерии фильтрации точно для индексируемого столбца, а не для выражения на его основе. Это было бы первым шагом.

Есть еще шаги:

  • Избавьтесь от столбца VARCHAR (10) для дат и замените его соответствующим столбцом DATE или DATETIME. Хранение даты и / или времени в виде строк пронизано проблемами. Не только для индексации, но и для корректности.
  • Таблица, которая часто сканируется в диапазоне на основе столбца (как и большинство таких таблиц журнала вызовов), должна быть кластеризована по этому столбцу.
  • Маловероятно, что вам действительно нужны столбцы yr и mnth. Если они вам действительно нужны, то они, вероятно, нужны как вычисляемые столбцы.

.

CREATE TABLE [dbo].[Calls](
    [CallID] [varchar](8) NOT NULL,
    [RecvdDate] [datetime](10) NOT NULL,
    [CallStatus] [varchar](50) NOT NULL,
    [Category] [varchar](100) NOT NULL,
    [QCall] [varchar](15) NOT NULL,
    [KOUNT] [int] NOT NULL,
    CONSTRAINT [PK_Calls_CallId] PRIMARY KEY NONCLUSTERED ([CallID]));

CREATE CLUSTERED INDEX cdxCalls ON Calls(RecvDate);

SELECT *
FROM Calls
WHERE RecvDate >= '12/01/2009';

Конечно, правильная структура таблицы и индексов должна быть результатом тщательного анализа с учетом всех факторов, включая производительность обновления, другие запросы и т. Д. Я рекомендую начать с просмотра всех темы, включенные в Разработка индексов .

0 голосов
/ 29 ноября 2010

Предполагая, что RecvdDate - это TicketRecvdDateTime, о котором вы говорите:

SQL Server сравнивает даты только в одинарных кавычках, если тип поля - DATE. Ваш запрос, вероятно, сравнивает их как VARCHAR. попробуйте добавить строку с '99 / 99/0001 'и посмотрите, будет ли она показана внизу.

Если это так, результаты вашего запроса неверны. Измените тип на ДАТА.

Обратите внимание, что VARCHAR плохо индексирует, DATETIME делает.

Проверьте план запроса, чтобы увидеть, использует ли он индексы. Если БД мала по сравнению с доступной ОЗУ, она может просто сканировать таблицы и хранить все в памяти.

РЕДАКТИРОВАТЬ: При просмотре вашего редактирования CAST / DATETIME, позвольте мне отметить, что анализ даты из VARCHAR является очень дорогой операцией. Вы делаете это 220k раз. Это убьет производительность.

Также вы больше не проверяете индексированное поле. сравнение с выражением, включающим поле индекса, не использует индекс.

0 голосов
/ 29 ноября 2010

Можете ли вы изменить свой запрос?Если требуется несколько столбцов, вы можете изменить предложение SELECT, чтобы оно возвращало меньше столбцов.И затем вы можете создать покрывающий индекс, который включает все столбцы, на которые есть ссылки, включая TicketRecvdDateTime.

. Вы можете создать индекс на TicketRecvdDateTime, но вы не можете избежать переломного момента, обсуждаемого @Randy Minder.Однако при сканировании с меньшим индексом (меньше, чем при сканировании таблицы) будет возвращено меньше страниц.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...