Когда условие в срезе последних даже вредит






Спойлер: оптимизатор MSSQL видит внешние, по отношению к срезу, условия, и строит план с их учетом.

Есть у нас регистр сведений с атрибутами документов. Строк в нем примерно 250 000 000. Да, миллионов. И иногда возникает естественное желание этим регистром воспользоваться. Например, так:

ВЫБРАТЬ
Документы.ИД    КАК ИД,
Срез_1.Значение КАК Атрибут1,
Срез_2.Значение КАК Атрибут2,
Срез_3.Значение КАК Атрибут3

ПОМЕСТИТЬ
ДокументыСАтрибутами

ИЗ
Документы КАК Документы

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АтрибутыДокументов.СрезПоследних(&ПериодСреза,
Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут1)) КАК Срез_1
ПО Документы.ИД = Срез_1.ИД

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АтрибутыДокументов.СрезПоследних(&ПериодСреза,
Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут2)) КАК Срез_2
ПО Документы.ИД = Срез_2.ИД

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АтрибутыДокументов.СрезПоследних(&ПериодСреза,
Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут3)) КАК Срез_3
ПО Документы.ИД = Срез_3.ИД

 

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

Программист идет в профайлер, смотрит время текущей версии запроса и видит это:

23 секунды, немного. Но и немало.

Пишет запрос, который выбирает атрибуты документов во временную таблицу. Добавляет условие по документам внутрь среза, потому что «так правильно» (https://its.1c.ru/db/metod8dev#content:2594:hdoc).

ВЫБРАТЬ
Срез.Атрибут  КАК Атрибут,
Срез.ИД       КАК ИД,
Срез.Значение КАК Значение
ПОМЕСТИТЬ
ВТЗначАтрибутов
ИЗ
РегистрСведений.АтрибутыДокументов.СрезПоследних(&ПериодСреза,

Атрибут В (ВЫБРАТЬ ВТ1.Атрибут ИЗ ВТАтрибуты как ВТ1)

И (ИД)
В   (
ВЫБРАТЬ
Документы.ИД
ИЗ
Документы
)
) КАК Срез

И соединяет полученную таблицу с документами

ВЫБРАТЬ
Документы.ИД    КАК ИД,

Срез_1.Значение КАК Атрибут1,
Срез_2.Значение КАК Атрибут2,
Срез_3.Значение КАК Атрибут3

ПОМЕСТИТЬ
ДокументыСАтрибутами

ИЗ
Документы КАК Документы

ЛЕВОЕ СОЕДИНЕНИЕ ВТЗначАтрибутов КАК Срез_1
ПО Срез_1.Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут1)
И Документы.ИД = Срез_1.ИД

ЛЕВОЕ СОЕДИНЕНИЕ ВТЗначАтрибутов КАК Срез_2
ПО Срез_2.Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут2)
И Документы.ИД = Срез_2.ИД

ЛЕВОЕ СОЕДИНЕНИЕ ВТЗначАтрибутов КАК Срез_3
ПО Срез_3.Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут3)
И Документы.ИД = Срез_3.ИД

Здесь небольшое отступление, чтобы восполнить пробелы в структурах данных.

Таблица с атрибутами содержит 3 строки со значениями перечислений.

ВЫБРАТЬ
ЗНАЧЕНИЕ(Перечисление.Атрибуты.Атрибут1) КАК Атрибут
ПОМЕСТИТЬ ВТАтрибуты
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ЗНАЧЕНИЕ(Перечисление.Атрибуты.Атрибут2)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ЗНАЧЕНИЕ(Перечисление.Атрибуты.Атрибут2)
ИНДЕКСИРОВАТЬ ПО
Атрибут

Таблица «Документы» довольно большая, там 300 000 строк.  Колонок в ней немного,  для данного примера это неважно.

ВЫБРАТЬ
Док.ИД  КАК ИД
ПОМЕСТИТЬ
Документы
ИЗ
Документ.Какой_то_документ
ГДЕ
Какие-то условия

Довольный 1С-ник запускает новый запрос в надежде получить значительный прирост скорости и немигающим взглядом смотрит в монитор:

Хуже в 5 раз. Почему? Да потому что количество атрибутов разное.  Атрибут 1 – 2000, Атрибут 2 – 120 000, Атрибут 3 – 120 000.

Посмотрим на планы запросов. Сначала на исходный, до оптимизации. Сервер считает, что лучше всего будет выполнить 3 поиска в регистре атрибутов по ИД документов (и, забегая вперед, скажу, что сервер прав).

 

 

После оптимизации получился другой план, в котором сервер посчитал, что будет лучше сначала сформировать срез атрибутов по всем документам, и лишь после этого отобрать нужные документы. Причем, слегка промахнулся в оценке, выбрав в итоге 70 млн строк, вместо 7 млн. Одна из причин замедления — самый правый IndexSeek, выполнившийся 70 млн раз.

 

 

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

Вот условие, о котором идет речь:

Атрибут В (ВЫБРАТЬ ВТ1.Атрибут ИЗ ВТАтрибуты как ВТ1)

А вот новые данные по запросу (на прогретом буфере).

План запроса вернулся к исходному состоянию (сравните с первым скриншотом, там 3 таких блока), что логично, т.к. запрос тоже вернулся к исходному.

Но это только срез последних. А ведь еще есть соединение с таблицей документов. На него тратится 5 секунд, и это нивелирует все усилия по оптимизации данного запроса.

Такой вот, безрезультатный результат.

P.S. Не то, чтобы я призываю к отказу от отборов в виртуальных таблицах, но иногда надо все же проверить, что получится в итоге оптимизации.

98 Comments

  1. vosd

    В регистре сведений в каком порядке идут измерения?

    Reply
  2. Поручик

    Посмотрим за дискуссией

    Reply
  3. triviumfan

    А существующие индексы нам знать не обязательно?

    Reply
  4. TMV

    Без структуры регистра не пойдет

    Reply
  5. nicxxx

    Измерения: ИД, строка (20); атрибут (перечисление). Кластерный индекс в формате 8.2, т.е. поле _period слева.

    Reply
  6. AHDP

    У документа есть атрибуты с разными датами?

    1) Можно пример документа. Как определяются даты реквизитов и как контролируется их «правильная» последовательность?

    2) Если отказаться от 1Совского среза последних, хотя бы для двух соедений, заменив их своим вариантом с дополнительным условием на дату документа/результата из первого среза, какие будут результаты?

    Reply
  7. mvk4d

    А почему не индексируете поля временных таблиц, по которым в дальнейшем идет соединение?

    Reply
  8. mvk4d

    https://its.1c.ru/db/metod8dev#content:5842:hdoc:index_condition_corr

    Цитата: «Внимание! Не забудьте проиндексировать созданную временную таблицу. В качестве индексных полей следует указать все поля, которые используются в условии соединения.»

    Reply
  9. caponid

    Мне почему-то режет взгляд первое измерение — строка — как то я не очень перевариваю их в регистрах…

    у вас индексы весят как и данные?

    почему то это мне напоминает статусы заказов..

    А можно подробнее об архитектуре регистра и чем она обусловлена?

    Reply
  10. kiruha

    (5)

    Выложите скрин структуры регистра сведений. Ничего не понятно.

    Что за секретность ?

    Reply
  11. triviumfan

    (5) Типичный регистр для таких целей.

    Ну так делать отбор для среза в данном примере бессмысленно, что и показано. Оптимизировать тут нечего, словом совсем.

    1й вариант — эталон, отбор по атрибуту, соединение по ИД, этого достаточно.

    Reply
  12. palsergeich

    (8) Индекс в общем то не бесплатный. И индексация 70 млн строк может привести к еще более интересным проблемам. Одна из рекомендаций 1с: эксперт — по возможности отказаться от индексации временных таблиц.

    Reply
  13. mvk4d

    (12) Понятно, спасибо. Но меня смущает слово «может». Пока не попробуем, не узнаем точно. Хотелось бы услышать мнение автора на этот счет.

    Reply
  14. CyberCerber

    (5) А что за измерение ИД (строка 20)? Это для связи с доками? Почему не ссылка на доки? И даже для гуида коротковата. Вы сами как-то идентифицируете уникальные доки?

    Reply
  15. nicxxx

    (7)индексируются. Посмотрите на второй план, там справа есть 2 оператора IndexScan. Т.е. можно было и не индексировать. Эксперты правильно советуют не индексировать, т.к. временная таблица, как правило, меньшего размера и NestedLoops использует ее в качестве внутренней. Это всегда Scan.

    Reply
  16. nicxxx

    (13) Индексируется. Но смысла в этом нет, т.к. в плане видно IndexScan.

    Reply
  17. lunjio

    Если не заморачиваться как в статье https://infostart.ru/public/551583/, то во-первых, нет необходимости три раза соединяться, можно 1 раз соединиться на таблицу и через выбор когда тогда значения устанавливать, использую группировку соответственно. Во-вторых, в каком порядке идут измерения «ИД» и «Атрибут», мне кажется атрибуты после ИД, почему в условии к виртуальной Условие на ИД не стоит первом и не оптимально было бы оставить только условие на ИД ? а на отбор с атрибутами не заморачиваться и сделать как написал выше.

    ВЫБРАТЬ
    Документы.ИД    КАК ИД,
    МАКСИМУМ(ВЫБОР КОГДА ЗначенияАтрибутов.Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут1) ТОГДА ЗначенияАтрибутов.Значение КОНЕЦ) КАК Атрибут1,
    МАКСИМУМ(ВЫБОР КОГДА ЗначенияАтрибутов.Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут2) ТОГДА ЗначенияАтрибутов.Значение КОНЕЦ) КАК Атрибут2,
    МАКСИМУМ(ВЫБОР КОГДА ЗначенияАтрибутов.Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут3) ТОГДА ЗначенияАтрибутов.Значение КОНЕЦ) КАК Атрибут3
    
    ПОМЕСТИТЬ
    ДокументыСАтрибутами
    
    ИЗ
    Документы КАК Документы
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АтрибутыДокументов.СрезПоследних(&ПериодСреза,
    ИД В (ВЫБРАТЬ Ф.ИД ИЗ Документы КАК Ф)) КАК ЗначенияАтрибутов
    ПО Документы.ИД = Срез_1.ИД
    СГРУППИРОВАТЬ ПО
    Документы.ИД

    Показать

    Можно попробовать с временной таблицей, следуя рекомендациям ИТС, но так тоже должно быть более оптимально.

    Reply
  18. nicxxx

    Секретности нет. Опубликовал статью и уехал в отпуск без компьютера. Не могу сделать скриншот со структурой регистра. Но состав полей я уже сообщил. Измерения: строка, ссылка на перечисление. Ресурс всего один — ссылка на справочник атрибутов. Выбрана такая структура, потому что нужна историчность атрибутов. Атрибута с типом Дата нет, поэтому альтернативный срез здесь неприменим.

    Reply
  19. q_i

    А если не пихать всё в одну временную таблицу ВТЗначАтрибутов, а сделать 3 временные таблицы:

    1. ВТЗначАтрибутов1 = СрезПоследних(&ПериодСреза, Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут1) И ИД В …)

    2. ВТЗначАтрибутов2 = СрезПоследних(&ПериодСреза, Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут2) И ИД В …)

    3. ВТЗначАтрибутов3 = СрезПоследних(&ПериодСреза, Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут3) И ИД В …)

    проиндексировать все их по ИД, а потом все связки со срезами последних из исходного запроса заменить на связки с этими таблицами?

    Reply
  20. kiruha

    (18)

    оричность атр

    Спасибо, не понял сразу что атрибут — ресурс

    Reply
  21. nicxxx

    (8) Совет по индексации временной таблицы даётся в расчете на то, что оптимизатор выберет MergeJoin. Это быстрее, чем NestedLoops, но вторая таблица также должна быть отсортирована.

    Reply
  22. nicxxx

    (9) Строка в измерении это не такое большое зло, как может показаться. Документы приходят из разных внешних систем. Длина ИД от 6 до 10 знаков, в юникоде это до 20 байт. Для сравнения, ссылка занимает 16 байт. В итоге оверхед получается не слишком значительный. Размер индекса нетрудно посчитать, два поля из трёх — примерно 66% от кластерного. Подумываю сделать покрывающий вместо стандартного, чтобы из плана ушла операция KeyLookup.

    Reply
  23. nicxxx

    (19) Интересная мысль, но может получиться так, то будет три раза использован второй план запроса и время из 110 секунд превратится в 330. Надо проверять.

    Reply
  24. nicxxx

    (3) Индексы стандартные, кластерный по периоду и 2 некластерных по измерениям.

    Reply
  25. herfis

    (21) Моя (и не только) практика показывает, что реальная польза от индексации временных таблиц — скорее исключение, чем правило. И ничего странного в этом нет, если подумать. Чаще всего временные таблицы не настолько велики, чтобы оптимизатор дал применению индексов зеленый свет. А на реально больших временных таблицах скорее всего хэш-таблицу строить будет.

    Reply
  26. VmvLer

    (17) из этого примера на громадных базах конечно условие

    ИД В (ВЫБРАТЬ Ф.ИД ИЗ Документы КАК Ф) должно оперировать с временной таблицей, а на очень больших базах я его еще и убираю из виртуальной таблицей в секцию ГДЕ.

    Условия в виртуальной таблице все-равно в SQL «соскакиваю» в ту же секцию ГДЕ.

    Reply
  27. caponid

    Документов порядка 300к, атрибутов 250 000к — в среднем порядок набора атрибутов на документ 1к

    А сколько документов участвует в типичном запросе? Все? или есть все таки какие то типичные ограничения?

    Reply
  28. A_Max
    ВЫБРАТЬ
    Документы.ИД,
    АтрибутыДокументов.Атрибут,
    АтрибутыДокументов.Значение,
    АтрибутыДокументов.Период
    ИЗ
    Документы КАК Документы
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ АтрибутыДокументов КАК АтрибутыДокументов
    ЛЕВОЕ СОЕДИНЕНИЕ АтрибутыДокументов КАК АтрибутыДокументов_Последний
    ПО АтрибутыДокументов.ИД = АтрибутыДокументов_Последний.ИД
    И АтрибутыДокументов.Атрибут = АтрибутыДокументов_Последний.Атрибут
    И АтрибутыДокументов.Период < АтрибутыДокументов_Последний.Период
    ПО Документы.ИД = АтрибутыДокументов.ИД
    ГДЕ
    АтрибутыДокументов.Атрибут В («Атрибут1», «Атрибут2»)
    И АтрибутыДокументов_Последний.ИД ЕСТЬ NULL

    Показать

    Ну а чтобы развернуть атрибуты в строку варианты можно как предложили (17) проверку в полях + группировка или поместить всё в ВТ и крутить как душе удобно добавив индексы.

    Reply
  29. triviumfan

    Я уже весь попкорн доел… сколько интересного!

    jpg

    Кому то структура регистра не нравится, кому-то строковое измерение…кто-то агрегацию использует, кто-то пытается переписать срез, кто-то рекомендует ИНДЕКСАЦИЮ ВТ! LOL

    Да нету тут ничего совсем! Оптимизировать НЕ-ЧЕ-ГО!

    Берём документы, делаем срез как было показано в первом примере, и никакой временной таблицы не надо — она лишняя.

    Для тех кто в танке и им все равно нужна структура этого периодического регистра:

    Изменения (по порядку): ИД, Атрибут

    Ресурсы: Значение

    Это типичный регистр для хранения доп. значений объектов!

    Reply
  30. kolya_tlt

    предлагаю оставить этот регистр в покое и использовать для истории (в смысле смотреть когда какой атрибут менялся), ввести второй — с текущими значениями атрибутов, т.е. 3 измерения ИД, Атрибут, Значение. понятное дело надо будет писать код обеспечивающий запись туда данных

    Reply
  31. nicxxx

    (27) Документов примерно 150 миллионов. Это за полгода. В примере рассмотрен типичный запрос с интервалом в три дня. Обычно на один документ приходится 2-4 атрибута, иногда ни одного.

    Reply
  32. nicxxx

    (30) За вас это уже сделала фирма 1С в платформе 8.3. Посмотрите на ИТС про итоги в регистрах сведений. Минусы этого подхода очевидны — рост времени транзакции на запись и рост размера таблицы. В моем случае прибавится примерно 80% от основной таблицы.

    Reply
  33. kolya_tlt

    (32)

    За вас это уже сделала фирма 1С в платформе 8.3. Посмотрите на ИТС про итоги в регистрах сведений. Минусы этого подхода очевидны — рост времени транзакции на запись и рост размера таблицы. В моем случае прибавится примерно 80% от основной таблицы.

    вы там так сильно заморачиваетесь и экономите место на харде? по-моему это последнее нам чем думают 🙂 рост времени транзакции пользователю будет абсолютно не заметен, а если вы возьмёте этот подход и не станете использовать возможности платформы — тем более.

    могу еще подкинуть идею сделать Ключи Атрибутов, сгруппировав записи регистра. т.е. в регистре будет одна запись вместо трёх и соответственно с тремя ресурсами. но тут надо посмотреть на статистику использования ваших атрибутов. в любом случае скорее вы не будете реализовать этот подход из-за большой трудоёмкости данного подхода.

    Reply
  34. nicxxx

    (28) А это вообще что? Срез последних из этого левого соединения не получится. И условие на NULL странное.

    Reply
  35. nicxxx

    Размер таблицы 200 ГБ:) вся база — 1.2 ТБ. На боевом сервере рэйд из SSD на 1.5 ТБ. Мы реально заморачиваемся и экономим место, т.к. диски недешевые. Про составное поле думал, но пока нет четкого представления, как перестроить бизнес-логику.

    Reply
  36. starik-2005

    Смысла индексировать таблицу из трех строк, конечно, нет никакого, ибо Лог2(3)=1,7 — выигрыш нулевой. По поводу срезов, то я бы от них отказался. Но тут зависит от того, сколько обычно вариантов атрибутов у документа. Как я понимаю, атрибуты документов могут меняться со временем. Если таких ситуаций -> 0, то смысла в срезе нет, а если их масса, то в идеале вообще производить выборку атрибутов как-то отдельно и потом уже соединять. Главное — минимизировать чтение из таблиц и избежать дополнительных упорядочиваний, добиться использования индексов без скана.

    Reply
  37. glog

    Я стараюсь такие большие таблицы выносить в отдельные базы и подключать их к 1С через внешние источники данных. Так гораздо больше возможностей по оптимизации (партицирование, сложные индексы и т.д.). Такой подход себя оправдывает не во всех случаях, конечно.

    Reply
  38. nicxxx

    (37) Невозможно хранить ссылки:( Также нельзя инсертить и джойнить с таблицами внутри базы.

    Reply
  39. Fox-trot

    все же не понятно почему вредит именно «условие срезе последних»

    Reply
  40. A_Max

    (34) Это именно срез последних и есть и именно за счёт вот этого странного условия на null

    Проверьте.

    Интересно увидеть план запроса на ваших данных. Генерировать у себя пока не стал.

    Reply
  41. herfis

    (40) Остроумная конструкция. Первый раз такую встречаю.

    Reply
  42. A_Max

    (41) Когда мне такой вариант получения среза показали я просто был в восторге от гениальной простоты (и до сих пор поражаюсь). А самое главное что можно делать срез по каким угодно критериям и измерениям/реквизитам и вообще не по регистрам, а по чём угодно!

    Reply
  43. herfis

    (42) Все способы ручного получения «последних» — универсальны.

    Что касается этого, было бы интересно сравнить производительность с классическим двух-этапным вариантом и вариантом с коррелирующим подзапросом.

    Reply
  44. nicxxx

    (36) Я ведь и попытался сделать выборку атрибутов отдельно. Сами видите к чему это привело.

    Reply
  45. nicxxx

    (40) Картинку видите в моем посте? Строки, где есть NULL, будут результатом вашего среза для моего регистра. Как-то не похоже на срез последних. Ошибки нет у вас? Если взять Макс(атрибуты_последний.период) и условие НЕ NULL, то становится больше похоже на правду.

    Reply
  46. A_Max

    (45) Очень сложно разбирать рукописную табличку. Ваш вариант можелировал запросом во вложении.

    Reply
  47. nvv1970

    (40) ну ну.

    Логически результат будет верный.

    Если в рс счёт идёт на миллионы строк, но такой подход быстро превращается в тыкву, ибо СУБД быстро отхлебнет

    Reply
  48. nvv1970

    Что-то не нашел ни решений, ни выводов… ни полных планов запроса (можно же сохранять по человечески, а не картинками).

    Ни структуры регистра… ИД надеюсь у вас первым стоит? Иначе быть беде…

    Интересно, какое время занимает скан индекса по измерениям?

    Не нашел теста такого варианта (не обязательно тестить 3 среза сразу):

        Документы КАК Документы
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АтрибутыДокументов.СрезПоследних(&ПериодСреза,) КАК Срез_1
    ПО Документы.ИД = Срез_1.ИД И Срез_1.Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут1)
    

    Из практики — он должен быть самым производительным.

    Плохо или хорошо условие в срезе — зависит от многих факторов: от самих условий, от типа соединения среза с внешней таблицей…

    Встречаю часто, что 1С любит в условия запросов (при условии в параметрах) добавлять EXISTS (SEL ECT 1 FR OM ….) — вот вам гарантированные NLoopsы и миллиарды/биллионы чтений.

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

    Да, есть советы и примеры, когда что-то явно тупит, но лучше иметь свой опыт. На чужом далеко не уедешь (

    Да, срез может сильно удивлять и доставлять проблемы (особенно с периодичностью по регистратору, или на PG), как вы ни пытаетесь лечь под индексы.

    Reply
  49. nvv1970

    (17) если убрать условие в параметрах, то план может быть проще, короче, быстрее. Оно ни к чему. Мсскл все равно строит план так, что нужная выборка будет получена «сразу», несмотря на многократную вложенность запросов.

    Reply
  50. alex-l19041

    (35)

    вся база — 1.2 ТБ

    КРУТО!

    Reply
  51. nicxxx

    (49) Вернусь из отпуска — попробую.

    Reply
  52. nicxxx

    (46) Проверил, действительно работает, как срез последних. Это я забыл, как строится left join:)

    Reply
  53. nicxxx

    (50) Ничего крутого. Backup — 50 минут, Restore — 40. Опыта конечно добавляет. Начинаешь думать о последствиях изменения любого флажка в реквизитах регистров. Становится единственным возможным способом включить индексирование на колонке — создать новый индекс в SSMS.

    Reply
  54. A_Max

    (52) Очень хочется план и результаты измерений для такого варианта увидеть.

    Был бы ОЧЕНЬ признателен. Да и другим тоже будет интересно и полезно думаю

    Reply
  55. nicxxx

    (54) Выложу в понедельник

    Reply
  56. nvv1970

    (56) ТЫ типичный 1с-ник?

    Откройте для себя планы запросов, уровни оптимизации запросов, логические и физические операторы, построение планов выполнения (читай — «порядка физических манипуляций с данными») и прочие области психиатрии.

    Но если вдруг вы со всем этим знакомы, то откуда такие выпады?

    Представьте три уровня вложенных запросов с условием только на внешнем уровне:

    Выбрать Поле Из (Выбрать Поле Из (Выбрать Поле Из Таблица)) Где Условие

    Вопрос: будет ли СУБД сканировать (получать по вашему) всю таблицу на вложенных уровнях?

    Ответ: конечно же нет.

    СУБД пошлет и 1с, и программиста в… и применит это условие на нижнем уровне.

    Вот такие разрывы шаблонов…

    Так и в моем примере… Наложение условий соединения будет выполненно в первую очередь, т.е. «на нижнем уровне».

    Reply
  57. kolya_tlt

    (35) слишком большая таблица, задумайтесь над тем чтобы её начать пилить. возможно некоторые атрибуты можно перенести в табличные части документа. как например был единый огромный регистр Значения свойств объектов, который был «размазан» по табличным частям объектов

    Reply
  58. nicxxx

    (58) Ее используют 2 вида документов, поэтому нет смысла делить. Вместо одной на 250 млн строк получим две, на 100 и 150 млн.

    Reply
  59. kolya_tlt

    (59) да, но типы таблиц то разные. там РС, а получите более простую. попробуйте перенести и выполнить замеры на тесте.

    Reply
  60. triviumfan

    (57)

    Так и в моем примере… Наложение условий соединения будет выполнено в первую очередь, т.е. «на нижнем уровне».

    Только если СУБД достаточно интеллектуальна. Мы же, свою очередь, должны помочь ей это сделать, чтобы СУБД выбрала оптимальный план.

    Но судя по вашему запросу, вы лишь затрудняете это.

    Reply
  61. Fox-trot

    (61)

    Но судя по вашему запросу, вы лишь затрудняете это.

    спорное утверждение

    Reply
  62. nicxxx

    (60) Это невозможно по архитектурным причинам. Документы тоже в регистре сведений:) В двух регистрах, если точнее. Почему? Так увидел архитектор(не я). Они затем агрегируются, чтобы записать не миллион проводок в хозрасчетный, а десять.

    Reply
  63. vasilev2015

    Зря Вы статью https://its.1c.ru/db/metod8dev#content:2594:hdoc цитировали. Там речь идет о виртуальной таблице срез последних с _отсутствующей_ датой среза. В платформе 8.3 такой запрос может обращаться к таблице итогов, использование параметров внутри полностью оправданно. У вас же дата среза используется.

    Reply
  64. vasilev2015

    Правда заключается в том, что виртуальные таблицы не все одинаково полезные. Например, таблица остатков полезна безусловно, а срез последних с датой или обороты с детализацией до регистратора — бесполезные, лучше обращаться к регистру напрямую.

    Reply
  65. Silenser

    Без доступа к базе конечно сложно говорить, но как вариант можно посмотреть фрагментацию индексов и статистику. Возможно их нужно перестроить и обновить, по дефолту SQL обновляет статистику не по всей таблице, а по ее части, что в некоторых случаях может иметь негативный эффект. Обычно указание отборов (не сложных) в параметрах виртуальной таблицы все же приводит к увеличению скорости запроса.

    Reply
  66. vasilev2015

    Готов на спор повозиться с вашим регистром и улучшить время запроса с 23 до 10 секунд ))

    Reply
  67. triviumfan
  68. nicxxx

    (67)Можно сгенерировать аналогичный объем строк и попробовать ускорить. Вся информация есть в топике и комментариях. Или могу продублировать сводно.

    Reply
  69. nvv1970

    (68) только не говорите такое Морозову, Богачеву… Они на экзамене или тренинге как раз пример такой приводят, что не все золото, что стандарт 1с. И разжевывают причину этого…

    Не бросайтесь злыми словами, а потрудитесь сравнить планы запросов и сами запросы в СУБД… Там все предельно просто и понятно. Причины на лицо.

    ПС: «достаточно интеллектуальна» — смешно… Вы окончательно меня убедили, что не владеете механизмами MSSQL или хотя бы PGSQL.

    Reply
  70. nvv1970

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

    Reply
  71. nvv1970

    (67) 10 сек — это тоже не решение. Вне зависимости от объема таблицы поиск по индексу и отсутствие миллиардных циклов — это всегда доли секунды. Много миллиардные таблицы тоже возвращают данные за 0.0ххх сек.

    Здесь или что-то вроде 0,5 или долгая дичь…

    Reply
  72. triviumfan

    (70) А вы не убедили меня, настаивая на том, что оптимизатор — «бог», он все сделает как надо.

    У меня есть платформа 8.2, sql2014, регистр с ценами на 70кк записей. Проведу тесты с очисткой статистики и кеша, а также поковыряюсь в настройках субд. Но я все же найду контрпример, чтобы заткнуть сего умника.

    Reply
  73. SlavaKron

    Пока нет возможности протестировать на сервере SQL. Шаблон для генерации данных в прикреплении.

    Reply
  74. nvv1970

    (73) ой все…

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

    Всегда можно сделать плохо. Это не нужно доказывать. Дурное дело не хитрое.

    А вот хорошо сделать не всегда получается.

    В 99.999% случаев (если специально не мешать) СУБД скомпилирует хороший быстрый план.

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

    Reply
  75. vasilev2015

    (72) Десять секунд — это время, полученное простым расчетом: вместо трех соединений использовать одно в три раза быстрее. И я тоже думаю, это не предел. Идея простая: использовать обращение к самой таблице регистра без среза.

    Reply
  76. vasilev2015

    (69) Поймите, когда я сгенерирую аналогичный объем и поспорю сам с собой, то выиграю спор самостоятельно. Я ожидал с Вашей стороны нормальное предложение спора.

    Reply
  77. nicxxx

    (77) Не понимаю смысла этого спора. Если у вас есть желание заняться оптимизацией, то все в ваших руках. Если получится сократить время до 10 секунд — ваше кунг-фу сильнее:)

    Reply
  78. vasilev2015

    (78) я занимаюсь оптимизацией либо за деньги либо за азарт. Вам ваш запрос безразличен или у Вас есть интерес его ускорить ?

    Reply
  79. triviumfan

    (75) Ясно, «слился». Мой «агр» был лишь на

    Из практики — он должен быть самым производительным.

    Он не может быть производительнее по определению, а лишь идентичен, либо проигрывает. Вот и всё.

    Reply
  80. nicxxx

    (79) Я помощи не просил. Ни за деньги, ни за азарт. Оптимизировать, отказавшись от среза я и сам могу. У меня уже есть процедура, которая по расписанию удаляет старые версии атрибутов. Ее лишь нужно подключить к продакшн-базе.

    Reply
  81. vasilev2015

    (81) да, попробуйте обращаться напрямую к регистру АтрибутыДокументов, группировать по полям Атрибут, ИД, максимум по полю Дата, условие Где Дата =< &ПериодСреза. Это должно работать быстрее чем срез последних три раза. Мне интересно, что получится. Напишите.

    Reply
  82. nvv1970

    (76) А у меня идея другая: добиться использования Merge, вместо медленного HashMatch. Без tf, гайдов и других «секретных» приемов (а-ля, ща покручу скуль)))).

    Идея простая: использовать обращение к самой таблице регистра без среза.

    Не туда смотрите. Какая разница? В СУБД в итоге вы сделаете один и тот же запрос, тот же плохой план, вид сбоку. Они только в 1с будут внешне отличаться.

    Reply
  83. vasilev2015

    (83) я указал в (82), какой запрос нужно сделать. Надеюсь, автор попробует.

    Reply
  84. nicxxx

    (84) Обязательно попробую, сразу после отпуска, в понедельник.

    Reply
  85. nicxxx

    (83)Чтобы получить Merge сначала надо сделать Sort, а это недешевая операция.

    Reply
  86. Fox-trot

    (81)

    У меня уже есть процедура, которая по расписанию удаляет старые версии атрибутов. Ее лишь нужно подключить к продакшн-базе.

    тады проще ваще удалить дату

    Reply
  87. nvv1970

    (86) все верно, но все относительно… Например, относительно хешджоина…)

    Пробуйте и расскажите нам.

    Reply
  88. nicxxx

    (40) План запроса пока не могу приложить, но время работы через left join и проверку на null в 10 раз хуже стандартного среза. Логических чтений в 15 раз больше

    Reply
  89. A_Max

    (89) Перечитал статью и комментарии.

    Атрибут 1 – 2000, Атрибут 2 – 120 000, Атрибут 3 – 120 000

    Документов 300 000

    Судя по всему получается, что атрибутов других ещё ОЧЕНЬ много так что в первую очередь нужно отсеить их.

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

    Нужен план и первого варианта и второго в котором с документом соединение третье, а не первое

    Оптимельность зависит от количество документов, атрибутов и количество «вариантов» значения одного атрибута.

    Reply
  90. nvv1970

    Вы забили на тему? Или не отошли ещё от отпуска?)))

    Reply
  91. nicxxx

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

    Reply
  92. w.r.

    А почему нельзя написать примерно так:

    ВЫБРАТЬ
    Документы.ИД    КАК ИД,
    ВЫБОР
    КОГДА Срез.Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут1) ТОГДА
    Срез.Значение
    КОНЕЦ КАК Атрибут1,
    ВЫБОР
    КОГДА Срез.Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут2) ТОГДА
    Срез.Значение
    КОНЕЦ КАК Атрибут2,
    ВЫБОР
    КОГДА Срез.Атрибут = ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут3) ТОГДА
    Срез.Значение
    КОНЕЦ КАК Атрибут3
    
    ПОМЕСТИТЬ
    ДокументыСАтрибутами
    
    ИЗ
    Документы КАК Документы
    
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.АтрибутыДокументов.СрезПоследних(&ПериодСреза,
    Атрибут В (ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут1),
    ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут2),
    ЗНАЧЕНИЕ(Перечисление.АтрибутыДокументов.Атрибут3)
    ))КАК Срез
    ПО Документы.ИД = Срез.ИД
    

    Показать

    И не нужно огород городить с 3мя соединениями к одному регистру

    Reply
  93. nicxxx

    Огород с тремя соединениями работает быстрее за счет технологии, называемой PREDICATE PUSHDOWN. Проверено на практике, я пробовал выполнить запрос, аналогичный вашему. Когда MSSQL джойнит виртуальную таблицу, то оптимизатор применяет фильтры, наложенные на главную таблицу. Смотрим на запрос ниже. Оптимизатор применит условие Doc.Ref IN() не только к таблице _Document123 , но и к таблице движений регистра накопления _AccumRg567.

    SELECT

    Doc.Ref,

    RegVT.Amount

    FROM

    _Document123 AS Doc

    LEFT JOIN (SELECT

    Reg.Recorder,

    Reg.Amount AS Amount

    FROM

    _AccumRg567 AS Reg

    GROUP BY

    Reg.Recorder) AS RegVT

    ON RegVT.Recorder = Doc.Ref

    WHERE

    Doc.Ref IN ( здесь какое-то условие отбора, например по количеству документов, помещающихся на одну страницу динамического списка).

    Почему оптимизатор так сделает? Потому что незачем читать лишние данные, которые все равно окажутся не востребованы в джойне, т.к. это LEFT JOIN.

    Кстати, Postgres так не умеет. Недавно столкнулся с проблемой тормозов в РЛС при пролистывании журнала. В фактическом плане запроса стало понятно, что Postgres читает 200 000 строк из таблицы регистра, а MSSQL на таком же запросе — всего 100. Время соответственно 10 сек на отображение 35 строк на PG и 1 сек на MSSQL. Вы все еще за экономию на лицензиях?

    Reply
  94. sergathome

    (94) это запредел для многих местных «гуру».»». ага. 🙂 Однако цена вопроса тоже становится слишком велика. Просто цена.MSSQL Standard (16 cores max)… Мильоны, Карл !!!

    Reply
  95. acanta

    (94)жалобу на сборку постгрес от 1с на хотлайн 1с отправляли?

    Reply
  96. nicxxx

    (96) Да. Но дело не в 1С, а в оптимизаторе Postgres.

    Reply
  97. nicxxx

    (95) Standard — до 24 ядер

    (https://www.microsoft.com/en-us/sql-server/sql-server-2017-pricing)

    лицензия на 2 ядра — 187000 руб

    (https://www.softmagazin.ru/soft/produkty_microsoft/sql_server/7NQ-01158)

    на 24 ядра — 4.5 млн руб.

    прошу прощения, 2,25 млн.

    Да, недешево.

    Reply
  98. sergathome

    (99) я,я, натюрлих. заграница тоже не дремлет. выбор становится всё сложнее…

    зы по 14-му — 16. Ну не суть, конечно.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *