Медленное время выполнения SQL-запроса с внутренними объединениями
Я использую Microsoft SQL Server Enterprise Edition (64-разрядная версия).
Время выполнения моего запроса составляет около 1 минуты.
Docum
таблица содержит строки ххххххххPers
таблица содержит строки хххххххPermarks
таблица содержит строки хххххх
Индексы на Docum
Таблица:
Индексы на Pers
Таблица:
Индексы на Permarks
Таблица:
PERSMARKS_pm_p_id
PERSON_MARKScode_AND_date_till_AND_end_date_
Запрос:
SELECT doc
FROM docum(NOLOCK)
INNER JOIN pers(NOLOCK) ON doc = p
INNER JOIN permarks(NOLOCK) ON pm = p
WHERE doccode IN (20, 21, 22, 23, 24, 25, 30)
AND pm_ = 14
AND (enddate IS NULL OR enddate > getdate())
AND (date_till IS NULL OR date_till > getdate())
Как я могу ускорить этот запрос?
Вот полный запрос, время выполнения 5 минут INTO #temp:
SELECT f
,0 AS viso
,count(DISTINCT p) AS el_budu
,0 AS vidinis
,0 AS pasirasyta
INTO #temp
FROM documents(NOLOCK)
INNER JOIN fo(NOLOCK) ON doc = fv
INNER JOIN for(NOLOCK) ON fve = f
INNER JOIN per(NOLOCK) ON doc = p
INNER JOIN tax ti(NOLOCK) ON p = ti
INNER JOIN permarks(NOLOCK) ON pm = p
WHERE pmtcode = 14
AND (
enddate IS NULL
OR enddate > getdate()
)
AND (
datetill IS NULL
OR datetill > getdate()
)
AND startdate >= '2015-01-01'
AND enddate <= '2015-12-31'
AND rtcode = 1
AND fvcode IN (25)
AND doccode IN (
20
,21
,22
,23
,24
,25
,30
)
GROUP BY fcode
Результаты выполнения плана: фото результатов
2 ответа
Я реструктурировал ваш запрос для моей читабельности. Я также добавил псевдонимы, поскольку они, по-видимому, должны быть представлены в ваших таблицах, что должно стать хорошей привычкой, особенно для тех, кто должен следить за вами или работать с вами и узнавать, откуда на самом деле поступают данные, не запрашивая структуры таблиц.
Вы присоединяетесь к таблице лиц, но на самом деле ничего не используете для записи человека, за исключением "p_id", чтобы присоединиться к таблице person_marks.
SELECT
d.doc_p_id
FROM
documents d (NOLOCK)
INNER JOIN persons p (NOLOCK)
ON d.doc_p_id = p.p_id
INNER JOIN person_marks pm (NOLOCK)
ON p.p_id = pm.pm_p_id
AND pm.pm_pmt_code = 14
AND (pm.pm_end_date IS NULL OR pm.pm_end_date > getdate())
AND (pm.pm_date_till IS NULL OR pm.pm_date_till > getdate())
WHERE
d.doc_dprt_code IN (20, 21, 22, 23, 24, 25, 30)
Посредством транзитивного процесса, если документы "doc_p_id" являются идентификатором лица, то их можно использовать для прямого перехода к таблице person_marks без объединения лиц, полностью удаляющих это из микса (если это не был просто пример, и вы будете получать личную информацию). позже для производственного запроса).
SELECT
d.doc_p_id
FROM
documents d (NOLOCK)
INNER JOIN person_marks pm (NOLOCK)
ON d.doc_p_id = pm.pm_p_id
AND pm.pm_pmt_code = 14
AND (pm.pm_end_date IS NULL OR pm.pm_end_date > getdate())
AND (pm.pm_date_till IS NULL OR pm.pm_date_till > getdate())
WHERE
d.doc_dprt_code IN (20, 21, 22, 23, 24, 25, 30)
Далее, для индексации я бы порекомендовал следующую таблицу / индексы для охвата индексов для критериев запроса, поэтому для разрешения записей не нужно переходить на реальные страницы данных.
table index
documents ( doc_dprt_code, doc_p_id )
person_marks ( pm_p_id, pm_pmt_code, pm_end_date, pm_date_till )
Наконец, поскольку вы (в настоящее время) захватываете только личный идентификатор, вы можете изменить его на
select DISTINCT d.doc_p_id ...
Таким образом, он возвращает только одну запись на человека (опять же, если вы на самом деле не собираете другие данные и не просто упрощаете запрос для целей публикации / поддержки).
На изображении выше я отметил столбцы с кластеризованным / некластеризованным индексом. Поправьте меня, если что-то не так написано на изображении выше. Мои очки, как показано ниже:
Есть ли у вас какой-нибудь кластерный индекс в таблицах документов и person_marks. Кажется, что на них есть все некластеризованные индексы. Если нет кластеризованного индекса, то некластеризованный индекс должен извлекать значения из таблицы, которая является дорогой, и вы не получите хороший план выполнения.
Сделайте кластерный индекс для pm_p_id и doc_p_id, если это возможно, если значения уникальны. Это поможет оптимизатору использовать соединение слиянием вместо хеш-соединения.
Используйте таблицу #temp