#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. Можно использовать первичный ключ в качестве некластеризованного индекса, когда есть лучший кандидат для кластеризованного индекса. Это зависит от запросов.