Published on

November 17, 2011

Изучение шаблонов запросов SQL Server

При работе с SQL Server важно понимать различные шаблоны запросов и их влияние на производительность. В предыдущей статье мы обсудили использование ключевого слова DISTINCT внутри подзапроса IN. Сегодня мы рассмотрим еще один распространенный шаблон – использование TOP 1 внутри подзапроса EXISTS.

Давайте начнем с простого примера. Рассмотрим следующий запрос:

IF EXISTS (SELECT 1 FROM PrimaryTable_Medium)
    PRINT 'Существует'
    
IF EXISTS (SELECT TOP (1) 1 FROM PrimaryTable_Medium)
    PRINT 'Тоже существует'

В этом случае мы проверяем, есть ли записи в таблице PrimaryTable_Medium. Первый оператор IF EXISTS просто проверяет наличие записей, в то время как второй использует оператор TOP 1, чтобы ограничить результат только одной записью.

При тестировании запроса мы обнаруживаем, что оба варианта имеют идентичные планы выполнения и характеристики ввода-вывода. Операторы индекса выполняют сканирование, потому что нет предиката, позволяющего выполнить операцию поиска. Однако SQL Server оптимизирует запрос, чтобы прочитать только минимальное количество данных, необходимых для оценки условия EXISTS. В результате время CPU минимально, а статистика ввода-вывода подтверждает, что выполняются только два чтения.

Теперь рассмотрим более сложный сценарий. Мы будем использовать подзапрос EXISTS внутри оператора IF EXISTS с дополнительной фильтрацией и агрегацией:

IF EXISTS (
    SELECT 1 FROM PrimaryTable_Medium
    WHERE RIGHT(SomeColumn,2) > 'HH'
    GROUP BY LEFT(SomeColumn,1)
    HAVING COUNT(*) > 1
)
    PRINT 'Снова существует'
    
IF EXISTS (
    SELECT TOP (1) 1 FROM PrimaryTable_Medium
    WHERE RIGHT(SomeColumn,2) > 'HH'
    GROUP BY LEFT(SomeColumn,1)
    HAVING COUNT(*) > 1
)
    PRINT 'По-прежнему существует'

В этом случае планы выполнения становятся более сложными из-за дополнительной фильтрации и агрегации. Однако результаты остаются теми же – оба варианта имеют идентичные планы выполнения, ввод-вывод и время CPU. Сканирование индекса читает весь индекс, потому что SQL Server должен вернуть все строки для выполнения агрегации и последующей фильтрации.

Наконец, давайте рассмотрим использование подзапроса EXISTS с коррелированным условием:

SELECT ID, SomeColumn
FROM dbo.PrimaryTable_Medium pm
WHERE EXISTS (SELECT 1 FROM dbo.Secondary s WHERE pm.SomeColumn = s.SomeColumn)

SELECT ID, SomeColumn
FROM dbo.PrimaryTable_Medium pm
WHERE EXISTS (SELECT TOP(1) 1 FROM dbo.Secondary s WHERE pm.SomeColumn = s.SomeColumn)

Опять же, планы выполнения для обоих вариантов идентичны. Оператор EXISTS сам по себе извлекает только минимальную информацию, необходимую для удовлетворения условия, поэтому добавление оператора TOP 1 не оказывает никакого влияния на производительность запроса.

В заключение, при использовании подзапроса EXISTS в SQL Server нет необходимости добавлять оператор TOP для ограничения результирующего набора. Оператор EXISTS уже оптимизирует запрос для извлечения только необходимой информации. Добавление оператора TOP 1 только увеличивает размер запроса без предоставления каких-либо преимуществ в производительности.

Click to rate this post!
[Total: 0 Average: 0]

Let's work together

Send us a message or book free introductory meeting with us using button below.