Неожиданное сканирование таблицы для id!= Id

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

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

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

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

varchar(15) not null primary key

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

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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

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

Удачи!

Ответ 4

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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

EDIT: попробуйте форум TechNet на http://social.msdn.microsoft.com/forums/en-US/sqldatabaseengine/threads/, чтобы сообщить о поведении.

Ответ 7

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

Ответ 8

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

    Create a constraint on the table where id = id?

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

Ответ 9

Я не знаю, почему id!= id занимает в этом случае так много времени (хотя "очевидный" субъективен - это не обязательно оптимизация, о которой я бы подумал... это кажется необычным запросом: декартовой однако, соединение является болезненным). Но в общем, попробуйте "где 1 = 0" - или если вы просто хотите схему, возможно, немного рискованно SET FMTONLY ON.

Изменить: просто увидели: "Мы не контролируем приложение, которое запускает этот запрос hundres раз в минуту"... хммм... это делает его сложным.

Ответ 10

Будучи менее знакомым с SQL Server, я думаю, что решение ниже также может применяться к SQL Server.

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

Ответ 11

Похоже на то, что у вас есть политическая проблема, маскирующаяся как техническая проблема. Вы можете потратить много времени и усилий на технические проблемы, но пока вы повторяете "мы не контролируем приложение", вы закрываете себя от политических опций.

Вы не можете управлять приложением, но вы, вероятно, можете организовать какое-то влияние. Сделайте все заинтересованные стороны осведомленными о том, как поведение этого приложения влияет на всех, кто использует эту базу данных (используйте графики, так как вы хотите быстро получить это сообщение для управления). И ясность это проблема для автора приложения или Microsoft, чтобы исправить. Это может привести к давлению на автора приложения или может дать ответ от руководства "O.K., fine. Let buy buy another database for this application".

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

Ответ 12

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

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

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

Ответ 13

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