У меня есть запрос, который случайным образом начинает использовать другой индекс вместо индекса, который он должен использовать, и производительность запроса ухудшается, поскольку он создает плохой план выполнения, и все последующие выполнения плохие. Запрос генерируется из приложения действием пользователя в приложении. Сгенерированный запрос всегда один и тот же с одним и тем же хэшем sql. Раньше, когда возникала эта проблема, я удалял плохой план из кеша и использовал хранилище запросов, я использовал хороший план выполнения, и запрос возвращался к нормальной производительности. Но сейчас это решение больше не работает. Запрос постоянно выбирает неправильный индекс и, следовательно, создает неправильный план выполнения. Индексы не фрагментированы и статистика тоже обновляется. См. приведенный ниже запрос:
SELECT test_.ROWID,
test_.*
FROM ******.test_table test_
WHERE test_.STOFCY_0 = @P1
AND test_.VCRTYP_0 = @P2
AND test_.VCRNUM_0 = @P3
AND test_.VCRLIN_0 = @P4
AND test_.REGFLG_0 <> @P5
AND test_.QTYSTU_0 < @P6
ORDER BY test_.STOFCY_0,
test_.UPDCOD_0,
test_.ITMREF_0,
test_.IPTDAT_0 Desc,
test_.MVTSEQ_0,
test_.MVTIND_0 Option (FAST 1)
Предполагается, что запрос всегда возвращает 1 строку.
Мне нужна помощь в устранении этой проблемы, так как я пробовал следующее, и, похоже, ничего не работает, чтобы исправить это навсегда:
Индекс DDL:
CREATE UNIQUE NONCLUSTERED INDEX [test_table_index] ON [test_table]
(
[STOFCY_0] ASC,
[VCRTYP_0] ASC,
[VCRNUM_0] ASC,
[VCRLIN_0] ASC,
[REGFLG_0] ASC,
[QTYSTU_0] ASC,
[UPDCOD_0] ASC,
[ITMREF_0] ASC,
[IPTDAT_0] DESC,
[MVTSEQ_0] ASC,
[MVTIND_0] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Кроме того... SELECT STJ_.ROWID, STJ_.* кажется странным выбором для запросов, сгенерированных приложением - он будет дважды возвращать столбец ROWID.
Похоже, вам лучше всего подойдет кластеризованный индекс (или даже первичный ключ) следующим образом (STOFCY_0, VCRTYP_0, VCRNUM_0, VCRLIN_0, UPDCOD_0, ITMREF_0, IPTDAT_0 Desc, MVTSEQ_0, MVTIND_0), тогда вы получите его в идеальном порядке и вообще не будете искать.
Добавьте CREATE INDEX DDL в качестве кода к вашему вопросу вместо изображений и загрузите планы по запросу @Charlieface. Я предлагаю переместить STJ_.REGFLG_0 в последний ключ индекса.
Также полное определение таблицы, показывающее первичный ключ, если таковой имеется, и все остальные столбцы и индексы.
Я добавил Index DDL, оба плана (хорошие и плохие), как было предложено @Charlieface
Вы можете форсировать план с помощью Query Store: learn.microsoft.com/en-us/sql/relational-databases/performance/…
Вы говорите: «Запрос должен всегда возвращать 1 строку». так почему ORDER BY заставляет механизм SQL создавать план выполнения, в котором не будет упорядочения???


Я не уверен, что ваш «хороший» план так уж хорош, в нем все еще есть поиск RID. Что, в свою очередь, также означает, что у вас нет кластеризованного индекса, еще один плохой знак.
Я думаю, вы должны сделать этот индекс кластеризованным, а не некластеризованным. Это означает, что запрос может быть полностью удовлетворен с помощью индекса, и поиск или сортировка вообще не требуются.
Вы также должны переместить два столбца неравенства REGFLG_0 и QTYSTU_0 в конец порядка индекса, чтобы сортировка работала правильно.
DROP INDEX STOJOU_STJ0 ON STOJOU;
CREATE UNIQUE CLUSTERED INDEX STOJOU_STJ0
ON STOJOU_STJ0
(
STOFCY_0 ASC,
VCRTYP_0 ASC,
VCRNUM_0 ASC,
VCRLIN_0 ASC,
UPDCOD_0 ASC,
ITMREF_0 ASC,
IPTDAT_0 DESC,
MVTSEQ_0 ASC,
MVTIND_0 ASC,
REGFLG_0 ASC,
QTYSTU_0 ASC
);
Надо сказать, дизайн немного подозрительный. Вам действительно нужно так много столбцов, чтобы получить уникальную строку? И ваши имена столбцов ужасны, вы должны использовать более описательные.
Я не могу решить, каким должен быть этот запрос, поскольку мы не можем его изменить. Мне нужно найти способ исправить это без изменения кода.
Я не прошу вас изменить код, я прошу вас изменить определения таблиц и индексов.
Я определенно могу изменить определение индекса, и это хорошее предложение изменить его на кластеризованный индекс, а также переместить два столбца неравенства REGFLG_0 и QTYSTU_0 в конец порядка индекса. Я попробую это обязательно. Спасибо @Charlieface
Пожалуйста, поделитесь планами запроса через brentozar.com/pastetheplan, так как скриншоты не очень полезны. Пожалуйста, также покажите свои полные определения таблицы и указателя, как текст, а не изображения. Вам нужно
SELECT *или вы можете ограничить выбор столбцов? И почему вы думаете, что "хороший" план лучше, он выглядит плохо, но не так плохо?