Проблема с производительностью базы данных SQL Server

У меня есть запрос, который случайным образом начинает использовать другой индекс вместо индекса, который он должен использовать, и производительность запроса ухудшается, поскольку он создает плохой план выполнения, и все последующие выполнения плохие. Запрос генерируется из приложения действием пользователя в приложении. Сгенерированный запрос всегда один и тот же с одним и тем же хэшем 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 строку.

Мне нужна помощь в устранении этой проблемы, так как я пробовал следующее, и, похоже, ничего не работает, чтобы исправить это навсегда:

  • Я пытался перестроить индексы и обновить статистику.
  • Удалите плохой план выполнения и принудительно установите хороший план выполнения с помощью хранилища запросов. Это работает в течение нескольких минут, но после этого запрос снова выбирает плохой план.
  • Кажется, что оптимизатор SQL оценивает неправильное количество строк.
  • У меня нет контроля над изменением запроса, так как он генерируется из приложения.
  • Пока запрос может использовать индекс, который я хочу использовать, запрос работает нормально.
  • Ранее прикрепленный индекс содержал только столбцы предложения OrderBy. Я также добавил столбцы предложения WHERE, но это также не заставляет запрос всегда использовать этот индекс.

Индекс 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]

Пожалуйста, поделитесь планами запроса через brentozar.com/pastetheplan, так как скриншоты не очень полезны. Пожалуйста, также покажите свои полные определения таблицы и указателя, как текст, а не изображения. Вам нужно SELECT * или вы можете ограничить выбор столбцов? И почему вы думаете, что "хороший" план лучше, он выглядит плохо, но не так плохо?

Charlieface 12.05.2023 15:18

Кроме того... SELECT STJ_.ROWID, STJ_.* кажется странным выбором для запросов, сгенерированных приложением - он будет дважды возвращать столбец ROWID.

AlwaysLearning 12.05.2023 15:25

Похоже, вам лучше всего подойдет кластеризованный индекс (или даже первичный ключ) следующим образом (STOFCY_0, VCRTYP_0, VCRNUM_0, VCRLIN_0, UPDCOD_0, ITMREF_0, IPTDAT_0 Desc, MVTSEQ_0, MVTIND_0), тогда вы получите его в идеальном порядке и вообще не будете искать.

Charlieface 12.05.2023 15:28

Добавьте CREATE INDEX DDL в качестве кода к вашему вопросу вместо изображений и загрузите планы по запросу @Charlieface. Я предлагаю переместить STJ_.REGFLG_0 в последний ключ индекса.

Dan Guzman 12.05.2023 15:30

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

Charlieface 12.05.2023 15:34

Я добавил Index DDL, оба плана (хорошие и плохие), как было предложено @Charlieface

Rachit Gupta 12.05.2023 15:47

Вы можете форсировать план с помощью Query Store: learn.microsoft.com/en-us/sql/relational-databases/performan‌​ce/…

David Browne - Microsoft 12.05.2023 16:07

Вы говорите: «Запрос должен всегда возвращать 1 строку». так почему ORDER BY заставляет механизм SQL создавать план выполнения, в котором не будет упорядочения???

SQLpro 15.05.2023 10:00
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
8
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не уверен, что ваш «хороший» план так уж хорош, в нем все еще есть поиск 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
);

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

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

Rachit Gupta 12.05.2023 15:52

Я не прошу вас изменить код, я прошу вас изменить определения таблиц и индексов.

Charlieface 12.05.2023 15:57

Я определенно могу изменить определение индекса, и это хорошее предложение изменить его на кластеризованный индекс, а также переместить два столбца неравенства REGFLG_0 и QTYSTU_0 в конец порядка индекса. Я попробую это обязательно. Спасибо @Charlieface

Rachit Gupta 12.05.2023 16:10

Другие вопросы по теме