Как я могу оптимизировать соединение с сортировкой по нескольким таблицам в T-SQL?


Как можно оптимизировать следующий запрос?

   SELECT TOP 50 *
     FROM A 
LEFT JOIN B ON A.b_id = B.id 
 ORDER BY A.number, B.name DESC

Я создал некластеризованный индекс на (A. number asc, A. creation_date desc), который включает все столбцы из A, и другой некластеризованный индекс на B. origination_date desc, который включает все столбцы из B (кроме текстовых столбцов). Ни один из этих индексов не используется в соответствии с фактическим планом выполнения из среды SQL Server Management Studio.

То, что, кажется, вызывает падение производительности, - это сортировка B. origination_date. Когда я изучаю фактический план выполнения в среде SQL Server Management Studio, я вижу ,что" сортировка Top N " по этим трем полям занимает 91% времени выполнения. Если я оставляю сортировку на B. origination_date, запрос завершается почти мгновенно, используя индекс на A.

Редактировать: Обновил запрос, чтобы предоставить лучший, более простой пример.

3 4

3 ответа:

Поскольку вы сортируете столбцы из двух разных таблиц, SQL Server должен объединить таблицы и выполнить сортировку. Как только таблицы объединены, индексы на отдельных таблицах не помогают сортировке. Индексированное представление может быть вашим лучшим выбором.

Я бы предположил, что A. число типа "%% " - это ваша проблема. Что это должно сделать? Вы не должны использовать like с подстановочным знаком в качестве первого символа, если вы хотите использовать индексы. Как это происходит, кажется, что фильтрация ни для чего, поскольку между подстановочными знаками нет ничего.

Без практического доступа трудно придумать жесткие и быстрые решения. Некоторые идеи и предложения:

Без соединения в таблице B все, что должен сделать SQL (с индексом на A. Number), это пройти до тех пор, пока он не найдет первые 50 строк, которые соответствуют вашему шаблону. Если значения "Number" относительно уникальны (не так много дубликатов [это кардинальность]), то и значение Creation_Date в индексе невелико.

Почему левое внешнее соединение в B? Это один к [нулю или один], или [ноль или несколько]? Если мощность мала (много дубликатов в A), то соединение должно четко найти "первые 50", иначе можно было бы подумать, что соединение не повлияет на производительность за пределами необходимости выполнения соединения). Я не вижу никакого индекса на B (кроме идентификатора столбца), который имеет здесь какое-либо значение. ГМ, у вас есть индекс на B.Id так ведь? Если нет, то это может сильно замедлить процесс (при условии, что B имеет значительное число строк, конечно).

Подробнее sepcifics, я бы хотел рассмотреть мощность соединения и порядок по столбцам, и очень внимательно посмотреть на план выполнения запроса" with join".


Добавления

Если A имеет низкую мощность (много дубликатов), то оптимизатор запросов может "подумать", что ему придется использовать много B.Id для разрешения заказа (что необходимо сделать, чтобы найти топ-50). Это может объяснить, почему он делает то, что делает.

Если они дадут 100% эквивалентные результаты, я бы рекомендовал заменить Левое соединение с внутренним соединением. В общем, планы запросов могут стать намного проще, когда действуют более ограничительные условия соединения.