Неожиданное сканирование таблицы на id! = Id - PullRequest
11 голосов
/ 16 мая 2009

Одно приложение вызывает большую нагрузку на нашу базу данных Sql Server 2005. Мы не контролируем приложение , которое выполняет этот запрос раз в минуту:

select id,col1,col2,col3 from table where id != id

Обратите внимание на id! = Id , что означает, что строка не равна самой себе. Неудивительно, что в результате всегда не найдено ни одной строки. Однако Sql Server выполняет сканирование кластерного индекса каждый раз, когда запускает этот запрос!

Столбец id определяется как:

varchar(15) not null primary key

В плане запроса указано огромное количество «Расчетное количество рядов». У кого-нибудь есть идея, почему Sql Server требуется сканирование таблицы, чтобы выяснить очевидное?

Ответы [ 13 ]

6 голосов
/ 16 мая 2009

Я бы подделал этот запрос ... абстрагировался бы от представления и дублировал бы запрос.

Переименуйте вашу существующую таблицу 'table' в 'table_org' или что-то еще, и создайте вид, подобный этому:

CREATE VIEW table
AS
SELECT * FROM table_org
WHERE id='BOGUSKEY'

Теперь вы должны провести 1 сканирование через таблицу первичного ключа, и оно (как и исходный запрос) ничего не должно найти. Приложение не знает никого мудрее ...

4 голосов
/ 16 мая 2009

Вы самая большая проблема, не сканирование таблицы. Ваши две самые большие проблемы:

  • У вас абсолютно бесполезный запрос, который выполняется 100 раз в минуту для вашей базы данных. Кстати, я предполагаю, что запрос на самом деле пытается получить имена столбцов из таблицы, как предлагает Марк Гравелл.

и, что более важно:

  • Вы не можете контролировать, кто или что обращается к вашей базе данных.

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

Удачи!

3 голосов
/ 16 мая 2009

Возможно, вы захотите сообщить службе поддержки SQL Server об этом запросе (id <> id, когда столбец определен как первичный ключ) и полном сканировании таблицы, которое он вызывает, и посмотреть, возможно, они захотят добавить в оптимизации в обработчике запросов, чтобы убедиться, что это не вызывает полное сканирование таблицы.

Либо так, либо поговорите со службой поддержки приложения, которое вы не можете контролировать.

РЕДАКТИРОВАТЬ: попробуйте форум TechNet на http://social.msdn.microsoft.com/forums/en-US/sqldatabaseengine/threads/, чтобы сообщить о поведении.

3 голосов
/ 16 мая 2009

Я видел этот тип запроса.

Скорее всего, разработчики создают предложения «ГДЕ» на основе пользовательского ввода, текущих настроек или некоторых других факторов. Во многих случаях, может быть экземпляром по умолчанию, им понадобится предложение WHERE, которое является просто заполнителем. Именно тогда они используют такие критерии, как «id! = Id», «1 <> 1» и т. Д.

«Сотни раз в минуту» также заставляет меня поверить, что это неправильный заполнитель по умолчанию.

Иногда они используют критерий, который выполняет обратное действие, всегда оценивается как true, если регистр по умолчанию требует все строки.

Это долгий путь, но я бы посоветовал посмотреть, можете ли вы изменить настройки приложения, и посмотреть, исчезнет ли этот запрос. Вы можете получить небольшой результирующий набор, но который будет выполняться реже и лучше обрабатываться SQL Server.

3 голосов
/ 16 мая 2009

Каждое значение сравнивается с остальными значениями n-1. вот почему он возвращает огромное количество для «Расчетное количество рядов». Для вышеуказанной проблемы лучше использовать не в.

Данная статья является хорошим указателем на вашу проблему. Я надеюсь, что это поможет вам. http://www.sqlservercentral.com/articles/Performance+Tuning/2924/

2 голосов
/ 17 мая 2009

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

    Create a constraint on the table where id = id?

Предложение where может возвращать только строки, нарушающие ограничение, которых по определению нет. Эта дополнительная (хотя и избыточная) информация может помочь оптимизатору в вашем случае. Он также может достичь квадратного корня из ничего, но в вашем случае я бы попробовал на всякий случай ...

2 голосов
/ 17 мая 2009

После прочтения ответов здесь и ваших правок, позвольте мне обобщить ваши варианты:

  1. Изменить MS SQL Server для обработки этого случая (в основном, обратитесь в службу поддержки Microsoft)
  2. Измените приложение, чтобы избежать этого, или сделайте это по-другому (в основном, обратитесь в службу поддержки компании, которая сделала приложение)
  3. Изменить на что-то, кроме SQL Server (если это разрешено приложением), которое обрабатывает этот случай
  4. Изменить на другое приложение

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

Сначала я бы попробовал решение 2, оно должно / должно занять самое короткое время для выполнения.

Если, с другой стороны, эта компания не хочет менять приложение, то я бы пошел с решением 4. Это серьезная ошибка производительности, и если компания не хочет или не может решить эту проблему, вы должны спросите себя, что еще скрывается за следующим углом?

2 голосов
/ 17 мая 2009

У вас есть некластеризованный индекс в столбце id? Если нет, то наиболее эффективным курсом всегда будет сканирование CIX. Попробуйте добавить NCIX в столбец ID - он все равно может выполнить сканирование, но по крайней мере это будет сканирование по очень маленькому индексу. Если бы вы работали на SQL Server 2008, вы могли бы создать отфильтрованный индекс (WHERE id <> id), и SQL Server использовал бы (пустой) отфильтрованный индекс для удовлетворения запроса.

1 голос
/ 17 мая 2009

Я подозреваю, что SqlServer не "знает", что! = (Должно быть "<>"?) Является антирефлексивным (то есть A! = A всегда ложно) ... он просто видит, что это не константа (зависит от значений из строки результатов) и, следовательно, помещает ее в фильтр результатов. Так что «где id <> id» потенциально очень отличается от «где 1 <> 1».

Теперь они, безусловно, могут заставить его обнаружить этот случай; но я думаю, что это просто не попало в их список приоритетов, потому что это где-то между «странным» и «глупым» делать это.

Да, приложение делает это отстой, я думаю, вы уже это знаете;)

1 голос
/ 17 мая 2009

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

Вы не можете управлять приложением, но, вероятно, можете организовать какое-то влияние. Информируйте все заинтересованные стороны о том, как поведение этого приложения влияет на всех, кто использует эту базу данных (используйте графики, поскольку вы захотите быстро донести это сообщение до руководства). И будьте уверены, это проблема для автора приложения или Microsoft, чтобы исправить. Это может привести к давлению на автора приложения или к ответу «Хорошо, давайте купим другую базу данных для этого приложения» со стороны руководства.

(Вы захотите получить ответ на вопрос, «Microsoft» «исправила» это в SQL Server 2008).

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