Если вы не разобрались в тонкостях работы базы данных, то использование новых средств языка T-SQL может привести к неожиданным результатам в плане производительности.

Я уже писал о том, как подходить к работе с датами в WHERE: Where To Do Date Math In Your Where Clause.

Но оказалось, что все то же самое справедливо для обработки часовых поясов.

Для начала создадим индекс:

CREATE INDEX c ON dbo.Comments(CreationDate);

Теперь представим, что нам нужно сделать запрос к таблице Comments с учетом часового пояса:

DECLARE @d datetime = '20131201';
SELECT 
    COUNT_BIG(*) AS records
FROM dbo.Comments AS c
WHERE c.CreationDate AT TIME ZONE 'UTC+12' >= @d
OPTION(RECOMPILE);
GO

Ждать мы будем долго. Я полагаю, что минута для вас — это долго. Для меня это так, потому что каждая минута ожидания — это время, когда я не занимаюсь чем-то более полезным. 

Минутку, пожалуйста
Минутку, пожалуйста

Мы написали плохой запрос. Проблема здесь в том, что мы пытаемся преобразовать значение в каждой строке таблицы в новый часовой пояс, а затем сравнить со значением, которое мы могли бы очень легко вычислить один раз и сравнить с CreationDate.

DECLARE @d datetime = '20131201';
SELECT    
    COUNT_BIG(*) AS records
FROM dbo.Comments AS c
WHERE c.CreationDate >= DATEADD(HOUR, 1, @d) AT TIME ZONE 'UTC-11'
OPTION(RECOMPILE);
GO

Теперь запрос выполняется гораздо быстрее.

Вот это да!
Вот это да!

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

На эту тему есть довольно много постов не так ли? Но важно помнить — вопрос не в том, что в условии находится слева, а что справа. Главное — что мы вычисляем:

  • Если данные (то, что мы храним физически) — их преобразование превращается в цирк.

  • Если значение (то, что мы вычисляем один раз через параметр, переменную или иным способом) — это гораздо меньшая нагрузка.


Завтра состоится открытое занятие, на котором поговорим о том, что нового появилось в SQL Server 2022. Обсудим, как новые фичи упростят жизнь разработчикам и DBA. Регистрация открыта по ссылке для всех желающих.

Комментарии (2)


  1. akakoychenko
    26.12.2022 13:42

    Эх... Помню, надо было джойнить по сложному условию со сравнением времен две огромные таблицы фактов с разными таймзонами за достаточно большой период времени, чтобы попасть на летне-зимнюю смену пояса, и когда увидел, что 160 ядер загружены, а прогресса нет, и выяснил причину, то вышло выкрутиться костылем. Сначала с точностью до часа сгрупировал все уникальные таймстампы, потом для каждой строки приджойнил назад на эту cte, вычислил смещение в часах, и после этого через dateadd получил приведенное время. Перф вырос раз в 10 или 100.

    Вообще, невероятно странно, что настолько ущербную особенность работы допустили в M$. По сути, для каждой отдельной строки происходит вызов к API операционной системы. Но, даже, если часок посидеть с ручкой и блокнотом, то можно придумать алгоритм, который покроет все возможные кейсы смен поясов, и при этом снизит количество вызовов на порядки.


  1. Akina
    26.12.2022 14:15
    +1

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