Как я могу улучшить скорость запроса SQL для поиска набора строк - PullRequest
0 голосов
/ 27 июня 2018

У меня есть таблица с именем T_TICKET со столбцом CallId varchar(30).

Вот пример моих данных:

CallId               | RelatedData
===========================================
MXZ_SQzfGMCPzUA      | 0000
MXyQq6wQ7gVhzUA      | 0001
MXwZN_d5krgjzUA      | 0002
MXw1YXo7JOeRzUA      | 0000
...

Я пытаюсь найти записи, которые соответствуют коллекции CallId. Примерно так:

SELECT * FROM T_TICKET WHERE CALLID IN(N'MXZInrBl1DCnzUA', N'MXZ0TWkUhHprzUA', N'MXZ_SQzfGMCPzUA', ... ,N'MXyQq6wQ7gVhzUA')

И у меня есть где-то от 200 до 300 CallId, которые я смотрю одновременно, используя этот запрос. Выполнение запроса занимает около 35 секунд. Могу ли я что-либо сделать со структурой таблицы, типом столбца, индексом или самим запросом, чтобы повысить производительность этого запроса?

В T_INDEX в настоящее время есть около 300 000 строк. CallId не уникален. И RelatedData не уникален. У меня также есть индекс (не кластеризованный) на CallId.

Я знаю основы SQL, но я не профессионал. Вот некоторые вещи, о которых я подумал:

  1. Измените тип CallId с varchar на char.
  2. Сократить длину CallId (это длина 30, но на самом деле, сейчас я использую только 15 байтов).

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

Будет ли какой-либо из этих вариантов значительно улучшен? Или я мог бы сделать что-то еще, чтобы сделать это быстрее?

Ответы [ 3 ]

0 голосов
/ 27 июня 2018

Ваша таблица - это то, что мы назвали куча (таблица без кластерного индекса) . Этот вид таблиц подходит только для загрузки данных и / или в качестве промежуточной таблицы. Я бы порекомендовал вам преобразовать вашу таблицу, чтобы иметь кластерный ключ. Хороший ключ кластеризации должен быть уникальным, статичным, узким, ненулевым и постоянно увеличивающимся (например, int / bigint тип данных идентичности).

Еще одним недостатком кучи является то, что если у вас на столе много UPDATE / DELETE, это замедлит ваш SELECT из-за переадресации записей. Цитата из Пола Рэндала о переадресованных записях:

Если запись пересылки происходит в куче, когда локатор записей указывает на это место, механизм хранения попадает туда и говорит: «О, на самом деле запись не здесь - она ​​там! Затем он должен выполнить еще один (потенциально физический) ввод-вывод, чтобы перейти на страницу с переадресованной записью. Это может привести к тому, что куча будет менее эффективной, чем эквивалентный кластерный индекс.

Наконец, убедитесь, что вы определили все свои столбцы на SELECT. Избегайте SELECT *. Я предполагаю, что вы испытываете table scan при выполнении запроса. Что вы можете сделать, это INCLUDE список всех столбцов в вашем SELECT в вашем индексе, например:

CREATE INDEX [IX_T_TICKET_CallId_INCLUDE] ON [T_TICKET] ([CallId]) INCLUDE ([RelatedData]) WITH (DROP_EXISTING=ON)
0 голосов
/ 27 июня 2018

Оказывается, на самом деле есть способ значительно оптимизировать мой запрос без изменения типов данных.

Этот запрос:

SELECT * FROM T_TICKET 
WHERE CALLID IN(N'MXZInrBl1DCnzUA', N'MXZ0TWkUhHprzUA', N'MXZ_SQzfGMCPzUA', ... ,N'MXyQq6wQ7gVhzUA')

использует NVARCHAR типы в качестве входных параметров (N'MXZInrBl1DCnzUA', N'MXZ0TWkUhHprzUA'...). Как я указал в своем вопросе, CallId - это VARCHAR. Sql Server преобразовывал CallId в каждой строке таблицы в тип NVARCHAR, чтобы выполнить сравнение, которое занимало много времени (хотя у меня есть индекс на CallId).

Мне удалось оптимизировать его, просто НЕ меняя типы параметров на NVARCHAR:

SELECT * FROM T_TICKET 
WHERE CALLID IN('MXZInrBl1DCnzUA', 'MXZ0TWkUhHprzUA', 'MXZ_SQzfGMCPzUA', ... ,'MXyQq6wQ7gVhzUA')

Теперь, вместо того, чтобы бегать более 30 секунд, требуется всего около 0,03 секунды. Спасибо за все комментарии.

0 голосов
/ 27 июня 2018

Во-первых, убедитесь, что типы одинаковы - либо VARCHAR(), либо NVARCHAR(). Затем добавьте индекс:

create index idx_t_ticket_callid on t_ticket(callid);

Если типы совместимы, SQL Server должен использовать индекс.

...