Медленное время выполнения 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 ...

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

введите описание изображения здесь

На изображении выше я отметил столбцы с кластеризованным / некластеризованным индексом. Поправьте меня, если что-то не так написано на изображении выше. Мои очки, как показано ниже:

  1. Есть ли у вас какой-нибудь кластерный индекс в таблицах документов и person_marks. Кажется, что на них есть все некластеризованные индексы. Если нет кластеризованного индекса, то некластеризованный индекс должен извлекать значения из таблицы, которая является дорогой, и вы не получите хороший план выполнения.

  2. Сделайте кластерный индекс для pm_p_id и doc_p_id, если это возможно, если значения уникальны. Это поможет оптимизатору использовать соединение слиянием вместо хеш-соединения.

  3. Используйте таблицу #temp

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