2010-11-29 2 views
4

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

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

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) 

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

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

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

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

EDIT: Вот запрос, который я пытаюсь запустить и проверить скорость таблицы. Я обычно ставлю из колонок, но только для простоты я использовал *:

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

EDIT 2: Итак, я упомянул, что я попытался создать таблицу со столбцом даты, которая содержала данные recvddate, но в качестве даты, а не варчар. Это то, что столбец TicketRecvdDateTime находится в запросе выше. Исходный запрос я бегу к этой таблице:

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

Что такое * точный запрос, который вы используете, пожалуйста? – gbn 2010-11-29 19:00:54

+0

Да, извините. Позвольте мне редактировать и добавлять. Я забыл включить. – spinon 2010-11-29 19:03:36

+0

Что такое TicketRecvdDateTime? Это где-то вычисленный столбец; или почему это не в вашей декларации таблицы? – 2010-11-29 19:13:39

ответ

4

Вы можете быть сталкиваясь, что упоминается как Переломный момент в SQL Server. Несмотря на то, что у вас есть соответствующий индекс в столбце, SQL Server может в любом случае решить выполнить сканирование таблицы, если ожидаемое количество возвращаемых строк превышает некоторый порог («точка опроса»).

В вашем примере это кажется вероятным, так как вы поворачиваете 1/4 числа строк в базе данных. Ниже приведена хорошая статья, которая объясняет это: http://www.sqlskills.com/BLOGS/KIMBERLY/category/The-Tipping-Point.aspx

4

SELECT * обычно будет плохо работать.

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

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

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

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

0

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

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

0

Предполагая RecvdDate является TicketRecvdDateTime вы говорите:

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

Если да, то ваши результаты запроса неверны. Измените тип на DATE.

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

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

EDIT: При просмотре вашего редактирования CAST/DATETIME позвольте мне указать, что синтаксический анализ даты из VARCHAR является очень дорогостоящей операцией. Вы делаете это 220k раз. Это убьет производительность.

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

3

Ваш запрос быстрее без индекса (или, более высокоточного, является той же скоростью, ж/или без индекса), так и индекс 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'; 

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

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