Низкая производительность индекса на SQL Server?

#sql-server #indexing #sql-server-2016

#sql-server #индексирование #sql-server-2016

Вопрос:

У меня есть следующий запрос, который выполняется за 14 секунд (что кажется мне чрезмерным):

 select top 20 App.Id
from
    App
    inner join Base on Base.Id = App.BaseId
WHERE    App.TermId = 1190676
ORDER    BY App.Id
 

Приложения.Id — это первичный ключ (int). База.Id — это первичный ключ (int). App.termID и App.BaseID являются некластеризованными индексами. Приложение.Term также является внешним ключом к таблице, не используемой в этом запросе.

Индексы на базе.Id, App.BaseID и App.termID имеют фрагментацию менее 0,5%.

База таблиц содержит 71 879 записей, а приложение — 16 238,898 записей. Приведенный выше запрос вернул бы только 796 661, если бы у него не было верхнего условия.

Если я удалю внутреннее соединение, запрос будет выполнен менее чем за 1 секунду.

Я мало что знаю о планах выполнения чтения, но, похоже, он ищет базу индексов.У Id была самая высокая стоимость (70%), но она составляла 0,0 секунды. В то время как сканирование кластеризованного индекса стоило 30%, но заняло 18,5 секунд.

Я запустил:

 DBCC CHECKTABLE ('dbo.Base', REPAIR_REBUILD)
DBCC CHECKTABLE ('dbo.App', REPAIR_REBUILD)
 

Звучит ли 14 секунд разумно? На что еще я могу обратить внимание? Есть ли какая-либо другая полезная информация из плана выполнения, которой я могу поделиться?

.sqlPlan можно найти здесь: https://pastebin.com/UxDvsPRk

12:52 Я протестировал следующее, и приведенный выше запрос на 1 секунду медленнее:

 CREATE NONCLUSTERED INDEX [ix_dbo_App_TermId_BaseId] ON dbo.App
(
    TermId, BaseId
)
 

1:14
По предложению я обновил индекс, чтобы быть:

 CREATE NONCLUSTERED INDEX [ix_dbo_App_TermId_BaseId] ON dbo.App
(
    TermId, BaseId
)
include (Id)
 

… запрос по-прежнему выполняется медленно. НО теперь, похоже, он работает медленно только при наличии ORDER BY. Само объединение длится менее 1 секунды.

Комментарии:

1. Вам нужно ANY 20 поведение? Разве ваш TOP не должен быть связан с ORDER BY предсказуемым результатом? Как выглядит план выполнения (пожалуйста, отправьте .sqlplan в pastetheplan.com , а не изображение)?

2. Не видя планов, для этого запроса я бы представил индекс App (TermId, Id) и Base (Id) был бы наиболее полезным (обратите внимание на порядок столбцов). Тогда вы получите очень быстрое объединение слиянием

3. @AaronBertrand Я добавил вставку в свой пост. Я предоставил order by . См.: pastebin.com/UxDvsPRk

4. Лучший способ поделиться планами — загрузить XML-файл плана для вставки плана . Таким образом, и графический план, и XML легко просматриваются.

5. Чтобы прояснить то, что говорит @Charlieface, вам нужен составной индекс, один индекс, который состоит из 2 столбцов. Он абсолютно прав. Возможно, вам удастся немного подправить это, сделав App.termID включенным столбцом в индексе App.BaseID, но я бы хотел проверить это, чтобы быть уверенным.

Ответ №1:

Медленные индексы могут быть вызваны, когда в одном индексе слишком много столбцов. Сначала посмотрите на индекс таблицы, чтобы узнать, сколько столбцов содержится в ключевых столбцах индекса (в свойствах индекса). это может быть одной из проблем. Столбец первичного ключа никогда не должен быть некластеризованным индексом. Внешний ключ должен быть некластеризован. попробуйте обновить индекс в базе.ИДЕНТИФИКАТОР кластеризованного индекса.

Комментарии:

1. База. Идентификатор — это первичный ключ, это кластеризованный индекс. Мой внешний ключ (App.termID) — это некластеризованный индекс.

2. Можно использовать первичный ключ в качестве некластеризованного индекса, когда есть лучший кандидат для кластеризованного индекса. Это зависит от запросов.