Оператор SQL с одинаковыми несколькими подзапросами, выполняющимися очень медленно

#sql #sql-server #tsql #sqlperformance

#sql #sql-server #tsql #производительность SQL

Вопрос:

Я надеюсь, что кто-нибудь здесь сможет мне помочь. Мне был предоставлен этот запрос, выполнение которого занимает много времени (более 30 минут). Я пытался переписать запрос, но пока безуспешно. Я публикую пример запроса, чтобы вы могли получить представление о том, что я пытаюсь сделать.

В таблице 1 2000 записей. Table2 содержит 2000000 записей.

Table2 может не содержать запись, которую он пытается найти. Поэтому нельзя использовать ПЕРЕКРЕСТНОЕ ПРИМЕНЕНИЕ или ВНУТРЕННЕЕ СОЕДИНЕНИЕ. Я думаю, что это можно решить с помощью LEFT JOIN, но я не смог найти способ переписать его.

 SELECT
    ID, A, B,

    CASE WHEN c IS NULL then
        (SELECT max(distinct c) FROM TABLE2 tbl2 WHERE tbl1.Id = tbl2.Id)
    ELSE
        C
    END as C,

    CASE WHEN d IS NULL then
        (SELECT max(distinct d) FROM TABLE2 tbl2 WHERE tbl1.Id = tbl2.Id)
    ELSE
        D
    END as D,

    CASE WHEN e IS NULL then
        (SELECT max(distinct e) FROM TABLE2 tbl2 WHERE tbl1.Id = tbl2.Id)
    ELSE
        e
    END as e,
    f, g, h, i
FROM TABLE1 tbl1
 

Вместо того, чтобы запускать запрос ‘select max’ 3 раза, есть ли способ объединить таблицу только один раз, чтобы «один и тот же» запрос не выполнялся 3 раза? Причиной максимального значения является то, что Table2 может содержать несколько записей с одинаковым идентификатором. В этом случае считайте Id как Order_Id с номерами нескольких строк заказа.
Надеюсь, это имеет смысл.

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

1. OUTER APPLY казалось бы, это то, что вы хотите. Хотя ничто не указывает на то, что это является причиной ваших проблем с производительностью. На самом деле вам нужно изучить план выполнения и определить, где используется время.

2. Попробуйте включить индекс table2 (id ASC, e DESC) .

3. Пожалуйста, поделитесь планом запроса через brentozar.com/pastetheplan . Мы не сможем помочь вам должным образом без этого

4. Не могли бы вы опубликовать определения таблиц?

5. используйте index и проверяйте execution plan реакцию

Ответ №1:

Казалось бы, ваш запрос должен сводиться к следующему, работает ли это для вас и работает ли лучше?

 select
    t1.ID, t1.A, t1.B,
    IsNull(t1.c, t2.c) C,
    IsNull(t1.d, t2.d) D,
    IsNull(t1.e, t2.e) E,
    t1.f, t1.g, t1.h, t1.i
from TABLE1 t1
outer apply (
    select Max(c) c, Max(d) d, Max(e) e
    from TABLE2 t2
    where t2.Id = t1.Id
)t2
 

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

1. Потрясающе! Похоже, это помогает. И теперь запрос занимает 33 секунды. Мне все еще нужно убедиться, что значения правильные, но это выглядит правильно и тааак намного быстрее.

2. Все еще занимает 10 минут, но это намного лучше, чем 30 минут до этого. Далее, я думаю, я начну изучать план выполнения и посмотрю, где теряется время. Я добавил индекс в таблицу 2, но выполнение простого «ВЫБРАТЬ * ИЗ таблицы2» и получение его для отображения всех записей занимает чуть более 3 минут, так что проблема заключается в этом. В таблице 2 около 2 миллионов записей. Действительно ли отображение в SQL Server с некластеризованным индексом должно занимать 3 минуты?

3. Существует много причин и неизвестных, вам нужно будет задать конкретный вопрос о производительности и предоставить подробную информацию о таблицах, существующих индексах и, в конечном счете, плане выполнения.

4. Кроме того, он составляет 1/3 от продолжительности и попадает в вашу таблицу2 один раз вместо 3 раз, так что, по крайней мере, это имеет смысл.