MS SQL Server: ваши статистики не работают! Так ли все плохо на самом деле?

27.09.22

База данных - HighLoad оптимизация

Состояние и качество статистик критически важны для эффективной работы системы. Но у заметной части типовых конфигураций статистики просто не могут работать эффективно. О том, почему так происходит и что с этим делать, на конференции Infostart Event 2021 Post-Apocalypse рассказал Александр Денисов.

Поговорим о том, как устроены статистики в MS SQL, почему 1С иногда мешает статистикам работать правильно, и чем это все заканчивается.

Сразу важное замечание – все, о чем я говорю, относится к MS SQL Server, потому что я здесь рассказываю в том числе и о том, что происходит «под капотом». В PostgreSQL и других СУБД это может работать по-другому. Поэтому важно, что это все описанное в первую очередь касается MS SQL Server .

Зачем нужны статистики?

От качества статистик зависят ваши планы выполнения запросов и, соответственно скорость выполнения этих запросов. Поэтому очень важно понимать, как статистики работают, и что на них влияет.

Все мы знаем, что SQL – это декларативный язык, который говорит, «что нужно получить», но не говорит – «как». А «как получать» – придумывает сам SQL-сервер в виде плана выполнения запроса (см. иллюстрацию ниже).

 

План выполнения запроса – это, по сути, инструкция, какие операции выполнить и в каком порядке, чтобы получить нужный результат. При этом, у СУБД есть несколько вариантов чтения данных (индексный поиск vs. сканирование) и также несколько способов эти данные связать друг с другом. Естественно, возникает вопрос – что выбрать?

Например, для того, чтобы связать данные двух таблиц, у нас есть три базовых варианта соединения:

  • Nested Loops – вложенные циклы;

  • Hash Match – соединение по хэш-таблице;

  • Merge Join – соединение слиянием

 

У каждого из этих вариантов свои плюсы и минусы.

  • Nested Loops хорошо подходит, когда у нас на входе, с одной стороны, большой набор данных, а с другой стороны – маленький. В этом варианте работают вложенные циклы, и когда мы по маленькому набору быстро проходим, то сразу находим, что нужно. Но Nested Loops чудовищно проседает, когда у нас с обеих сторон большие наборы данных – скажем, для каждой из миллиона строк одного набора надо выполнить поиск по миллионам строк второго набора. Обычно так и возникают многочасовые ожидания выполнения запроса.

  • Hash Match – наоборот, очень хорошо работает с большими наборами, каждый из них будет прочитан по одному разу. Два скана для больших наборов – это гораздо лучше, чем миллионы и миллиарды повторяющихся поисков, как было бы с Nested Loops. Но с другой стороны, если из каждого из этих наборов нам нужно отобрать по несколько строк – это будут избыточные чтения, а также избыточное потребление оперативной памяти.

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

Статистики – это объекты в базе данных, которые хранят распределение данных внутри таблицы. Это выглядит приблизительно так, как на рисунке ниже.

 

 

Например, у нас есть таблица с контрагентами или физлицами. Она огромная – там миллионы записей. Мы просто посчитали распределение по этим записям, составили гистограмму и после этого понимаем – сколько у нас людей на букву А, сколько на букву Б и т.д.

И уже дальше SQL-сервер, когда готовит план выполнения, смотрит в эти гистограммы, примерно прикидывает, сколько ему строк в каждом случае вернется, и после этого может построить правильный план, который порадует и вас, как администраторов, которые следят за ресурсами, и пользователей, которые ждут, что этот запрос очень быстро выполнится.

 

Как физически устроены статистики?

Давайте посмотрим, как физически организованы статистики.

Отдельная статистика существует для каждого индекса, поэтому изучим статистику для индекса по «наименованию» справочника «Контрагенты». Я посмотрел соответствующие названия полей через оператор «ПолучитьСтруктуруХраненияБазыДанных» – в вашей базе названия SQL-объектов могут отличаться!

Для того,чтобы заглянуть статистике «под капот», воспользуемся старой, хорошо документированной командой

dbcc show_statistics

 

Сразу замечу, что это уже достаточно устаревшая команда. Всё дело в том, что она требует повышенных прав и возвращает сразу 3 набора данных. В результате она совершенно не подходит для применения в каких-нибудь скриптах или даже обычных запросах. Если вы пытаетесь что-то автоматизировать и вам нужна информация о статистиках, посмотрите документацию о DMV, например sys.dm_db_stats_histogram.

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

И тут я напомню, как должны выглядеть статистики здорового человека. Это вот такая красивая гистограмма: видно, что у нас все распределение разбивается на несколько столбцов, в каждом из которых какое-то количество строк (не обязательно одинаковое!)

 

 

Теперь давайте посмотрим, что я увидел в тестовой базе 1С. Конечно, я ее немного накачал данными – у меня в справочнике получилось 4.5 миллиона строк. Но картинка получилась вот такая:

 

 

4.5 миллиона строк и всего один шаг в статистике. Это просто смешно. Получается, как в том анекдоте про среднюю температуру по больнице. Внизу труп, наверху у нас горячка, посередине у нас какие-то непонятные 76,7 тысяч строк просемплировано. Это совершенно бессмысленно. У нас всего один шаг, и с каким бы значением параметра мы не пришли, выбирая наш план запроса, мы все равно придем к одной и той же оценке – одинаково плохой для всех вариантов. И план у нас будет всегда одинаково плохой.

Почему так выходит? Смотрим дальше. Я уже говорил, что dbcc show_statistics возвращает три набора данных – второй из них нам сейчас объяснит, в чем дело.

 

 

Вот у нас колонки, по которым строится статистика. И, если мы говорим про статистику, которая привязана к индексу, она всегда строится по первой колонке в индексе.

А какая у нас колонка во всех индексах типовой конфигурации? Правильно, «разделитель учета», который всегда равен одному и тому же значению!

Даже если у вас несколько баз, несколько организаций, несколько разделителей учета, они все равно никак не коррелируют, не релевантны всем последующим значениям в строке. Зная разделитель учёта из строки, вы не можете сказать, какой в этой строке контрагент – Вася или Петя. С равной вероятностью может быть любой. То есть мы строим статистику по нерелевантному, одинаковому значению, а все остальные значения из строки у нас оказываются за бортом.

Да, есть ещё мера корреляции (вторая и третья строки на рисунке выше), но это опять корреляция к одному-единственному значению. То есть, та же самая «средняя температура по больнице». Такая статистика оказывается просто бесполезна.

Признаюсь, когда я в первый раз увидел эту картинку, у меня была реакция, как у героев «Бриллиантовой руки», потому что это правда катастрофа.

 

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

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

 

Посмотрим, как это работает «вживую»

Я решил детально изучить, как выбирается и выполняется план выполнения на 1С-базе. В этом мне очень сильно помог SQL Server. Дело в том, что начиная с версии SQL Server 2014 SP2 прямо в плане запроса показано, какие статистики использовались при составлении этого плана. Можно даже посмотреть, в каком состоянии были эти статистики – когда они в последний раз пересчитывались, сколько изменений накопилось и т.д.

 

Чтобы получить план выполнения запроса из 1С, можно использовать привычный всем SQL Profiler, но это старая технология, которую уже лет 15 грозятся «похоронить» с каждым следующим релизом SQL Server. И есть за что – работающий профайлер, особенно собирающий планы запросов, может просадить скорость работы СУБД в несколько раз.

Вместо этого я воспользовался расширенными событиями (Extended Events). Эта технология существует в SQL Server те же самые 15 лет, но сделана специально для того, чтобы легковесно, с минимальной нагрузкой, собирать те данные, которые вам нужны для какого-то расследования или просто для мониторинга.

Слава Богу, что начиная с SQL Server Management Studio 2014 появился удобный интерфейс работы с расширенными событиями – больше не надо разгребать тонны XML, чтобы найти в них нужную информацию. Теперь же в Management Studio появилась отдельная «папка», посвященная работе с расширенными событиями. Удобные мастера для настройки событий и фильтров. И интерфейс для изучения собранных данных.

 

Для расследования тяжелых запросов возьмём готовый набор Query Detail Tracking.

 

Добавим туда очень важное событие query_post_execution_plan. На самом деле, мне бы и обычного estimated-плана хватило бы, потому что этот предварительный план уже все знает о тех статистиках, которые нам нужны. Но query_post_execution_plan – это самый максимальный вариант, самая подробная статистика, которую можно получить. (правда, ценой повышенной нагрузки на систему)

Я всех призываю посмотреть, что хранится в actual execution plan – плане, который мы получаем при выполнении запроса. Это – бесценный кладезь, огромное количество полезной информации. Тем более, что разработчики MS SQL Server расширяют этот набор от версии к версии.

  • Там есть информация по статистикам, про которую я уже говорил.

  • Есть рекомендации по индексам – про это тоже уже наверняка все знают, многие видели и используют.

  • В новых версиях добавили список флагов трассировки, которые в данный момент у вас включены.

  • Самое крутое – если у вас есть этот actual execution plan (план выполнения с реальной статистикой), в последних версиях вы можете видеть время, которое было затрачено на каждую операцию. Т.е. если у вас тормозит запрос, если вы не знаете, что делать – просто получаете actual plan. Да, это дорого, это тяжело с точки зрения производительности. Но это бесценно. И прямо смотрите в плане – на эту операцию у меня ушло 2 секунды, на эту – 10 секунд. Значит, именно сюда я буду смотреть и расследовать.

В общем, всем рекомендую, кто еще не видел и не пользовался – это просто бесценная вещь.

Так вот, настраиваем нашу сессию расширенных событий и смотрим, что у нас получается.

 

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

 

Смотрим подробно на план и видим, что сверху у нас – индексная статистика (она не подсвечена), а внизу – вот эта непонятная автоматическая статистика. SQL Server понимает, что обычная индексная статистика совершенно бесполезна. Поэтому он начинает перебирать варианты, смотрит, что у нас еще есть, и вот, на счастье, находит автоматическую статистику, которая помогает нам все-таки понять какое-то реальное распределение данных. И таким образом все-таки получить эффективный план запроса.

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

Я посмотрел на эту картинку, очень порадовался. Вселенная спасена, все классно, запросы работают. Но тут во мне проснулся лесоруб из анекдота. Ну помните, когда мужикам привезли модную японскую пилу. Они озадаченно посмотрели на чудо техники, сначала скормили ей веточку – распилила. Скормили ей брёвнышко – распилила. Дали ей 50-летний дуб – прожужжала, подумала, но распилила. Сунули ей стальной рельс – тут она и встала. «То-то же!» – сказали мужики и успокоились.

Вот я тоже пошел искать этот рельс, потому что ну не может все быть настолько хорошо, где-то должен быть какой-то подвох.

 

А если нужных статистик нет?

Подвох я, естественно, очень быстро устроил.

 

Я просто скопировал свою таблицу с 4,5 миллионами записей, создал все индексы, а автоматические статистики создавать не стал – решил посмотреть, что нам на это SQL Server скажет. На скриншоте выше как раз видно, что индексные статистики я здесь все вывел, а кроме индексных статистик ничего нет.

Выполняем запрос в Management Studio. Запрос на удивление выполняется – никаких проблем нет. Смотрим, что у нас попало в нашу сессию расширенных событий.

Вот он наш запрос Select TOP 30 – обычный классический запрос из формы списка, который выгребает какие-то данные:

 

А выше по списку, перед этим запросом – что-то интересное. Этот запрос появился ниоткуда, я его не заказывал, и в нем очень подозрительное слово StatMan.

На самом деле, это – запрос создания автоматических статистик.

 

Если мы теперь посмотрим на план выполнения запроса, мы опять увидим автоматическую статистику, которой буквально секунду назад еще не было – мы это проверяли по Management Studio.

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

Отсюда вывод – если у нас нужных статистик вообще нет, но автосоздание статистик включено, MS SQL их автоматически создаст при первой необходимости.

 

Какие выводы из этого можно сделать?

 

Если вы успеваете пересчитывать все ваши статистики за ночь, ничего делать и не нужно. «Лучшее – враг хорошего» или «работает – не трожь» – кому какая формулировка больше нравится.

Серьезно. Не нужно усложнять свой регламент обслуживания заранее. Если вы будете городить какие-то скрипты, потом об них сами же споткнетесь. Пока это работает – пусть работает.

 

Если вы начинаете новый проект, заводите какую-то новую базу, десять раз подумайте, нужен ли вам разделитель учета. Если он вам не нужен, я вам серьезно рекомендую его удалить, потому что ваши индексные статистики после этого будут работать эффективно – это не будет какой-то бесполезный балласт, который зачем-то у вас место занимает. И всем от этого будет жить легче – и MS SQL Server, и вам тоже. И с обслуживанием, и с сопровождением базы вам потом будет проще.

 

Если у вас уже большая база, есть разделитель учёта и очень маленькое регламентное окно и вы уже не успеваете пересчитывать все ваши статистики, тут выбор очень простой. Вы можете просто пропустить все индексные статистики, где используется разделитель учёта. Серьезно. От них нет никакого толку, пересчитывать их не нужно. Я бы еще рекомендовал здесь автоапдейт статистик отключить, чтобы эти автоматические статистики даже стали случайно не пересчитывались.

 

И еще одна, последняя рекомендация – очень важная, особенно для больших баз. Если у вас обновление конфигурации производится по классике и используется реструктуризация первого типа (т.е. мы не используем этот новый модный тип, когда у нас вызывается ALTER TABLE), тогда в результате обновления у вас создаются новые таблицы, и в них переливаются данные. В итоге получается картинка, как на моем втором эксперименте, когда данные есть, а автоматических статистик нет. И это очень хорошая причина, чтобы сразу после реструктуризации заранее выполнить все ваши топовые запросы:

  • вы прогреете кеш, у вас все данные сразу в оперативку поднимутся;

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

 

*************

Данная статья написана по итогам доклада (видео), прочитанного на конференции Infostart Event 2021 Post-Apocalypse.

См. также

HighLoad оптимизация Технологический журнал Системный администратор Программист Бесплатно (free)

Обсудим поиск и разбор причин длительных серверных вызовов CALL, SCALL.

24.06.2024    5307    ivanov660    12    

56

HighLoad оптимизация Программист Платформа 1С v8.3 Бесплатно (free)

Метод очень медленно работает, когда параметр приемник содержит намного меньше свойств, чем источник.

06.06.2024    9465    Evg-Lylyk    61    

44

HighLoad оптимизация Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Анализ простого плана запроса. Оптимизация нагрузки на ЦП сервера СУБД используя типовые индексы.

13.03.2024    5179    spyke    28    

49

HighLoad оптимизация Программист Платформа 1С v8.3 Бесплатно (free)

Оказывается, в типовых конфигурациях 1С есть, что улучшить!

13.03.2024    7705    vasilev2015    20    

42

HighLoad оптимизация Инструменты администратора БД Системный администратор Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Обработка для простого и удобного анализа настроек, нагрузки и проблем с SQL сервером с упором на использование оного для 1С. Анализ текущих запросов на sql, ожиданий, конвертация запроса в 1С и рекомендации, где может тормозить.

2 стартмани

15.02.2024    12592    250    ZAOSTG    83    

115

HighLoad оптимизация Системный администратор Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Принимать, хранить и анализировать показания счетчиков (метрики) в базе 1С? Почему бы нет? Но это решение быстро привело к проблемам с производительностью при попытках построить какую-то более-менее сложную аналитику. Переход на PostgresSQL только временно решил проблему, т.к. количество записей уже исчислялось десятками миллионов и что-то сложное вычислить на таких объемах за разумное время становилось все сложнее. Кое-что уже практически невозможно. А что будет с производительностью через пару лет - представить страшно. Надо что-то предпринимать! В этой статье поделюсь своим первым опытом применения СУБД Clickhouse от Яндекс. Как работает, что может, как на нее планирую (если планирую) переходить, сравнение скорости работы, оценка производительности через пару лет, пример работы из 1С. Все это приправлено текстами запросов, кодом, алгоритмами выполненных действий и преподнесено вам для ознакомления в этой статье.

1 стартмани

24.01.2024    5783    glassman    18    

40

HighLoad оптимизация Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Встал вопрос: как быстро удалить строки из ТЗ? Рассмотрел пять вариантов реализации этой задачи. Сравнил их друг с другом на разных объёмах данных с разным процентом удаляемых строк. Также сравнил с выгрузкой с отбором по структуре.

09.01.2024    14552    doom2good    49    

71
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. booksfill 28.09.22 16:24 Сейчас в теме
Спасибо за интересную статью, особо за рассказ про чудеса с разделителем данных.
Лично для меня последнее стало неожиданностью, как-то даже и не задумывался.
yaguarrr; olexi2012; Филин; +3 Ответить
2. redfred 29.09.22 05:20 Сейчас в теме
На самом деле всё немного не так, как вы думаете.

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


Нет, Sql Server ничего не понимает и не начинает в панике перебирать варианты где бы найти более лучшую статистику, с заглядыванием в автостатистики. Он без вариантов берёт и заглядывает в них и использует данные оттуда совместно с данными из статистики индекса. А не вместо них. Более того, это поведение так называемого "new cardinality estimator", который появился в 2014 SQL сервере. Если у вас работает legacy cardinality estimator (например уровень совместимости базы по какой-то причине стоит ниже 120) то автостатистика в данном случае будет игнорироваться, а план будет строиться исходя только из индексной статистики. Поэтому её стоит обслуживать в любом случае
3. Филин 371 29.09.22 10:27 Сейчас в теме
(2) Ок, согласен, тут я упростил ситуацию. Если говорить формально, то вообще все статистики, упоминаемые в плане, участвовали в его (плана) формировании. И индексная статистика по разделителю там тоже будет упоминаться, потому что СУБД к ней обращалась (хотябы за тем, чтобы убедиться, что она бесполезна)

Я не нашёл упоминаний о том, что в legacy CE используется только индексная статистика. Вообще, упоминание новшеств в CE довольно скудное - я нашёл только такое описание наиболее ранней версии https://cloudblogs.microsoft.com/sqlserver/2014/03/17/the-new-and-improved-cardinality-estimator-in-sql-server-2014/ И нигде не нашёл ничего про то, что CE раньше игнорировал автостатистики (кстати, а зачем они тогда вообще были нужны?).
Проверить это при помощи плана невозможно - при уровне совместимости меньше 120 данные о статистиках не попадают в план. Наверное, можно изучить диагностические выводы от флагов трассировки, но я не готов сейчас погружаться так глубоко: история слишком нишевая
Главный аргумент против этой версии у меня такой: разделитель учёта появился раньше нового CE, при этом SQL Server и в 2008, и в 2012 версиях умудрялся создавать вменяемые планы, правильно оценивая содержимое таблицы. Как видно из содержимого индексной статистики, она в этом никак не помогает.

Ну и ещё раз про обслуживание индексной статистики по разделителю. Как видно из DBCC SHOW_STATISTICS, на весь индекс там один-единственный диапазон. Я, честно, не вижу принципиальной разницы, какое число будет стоять по этому диапазону - 100 или 100 000. В любом случае оно будет далеко от реальных потребностей CE. Поэтому всё ещё не вижу смысла целенаправленно пересчитывать индексную статистику по разделителю учёта.
4. redfred 29.09.22 15:25 Сейчас в теме
(3)
И индексная статистика по разделителю там тоже будет упоминаться, потому что СУБД к ней обращалась (хотябы за тем, чтобы убедиться, что она бесполезна)


Опять же, нет. SQL сервер никак не оценивает полезность или бесполезность конкретной статистики. Можете, например, вот тут почитать, как там расчёт происходит, всё достаточно незамысловато - https://www.sqlskills.com/blogs/kimberly/multi-column-statistics-exponential-backoff/

(3)
Я не нашёл упоминаний о том, что в legacy CE используется только индексная статистика.


А я не говорил, что он всегда использует только индексную, а автостатистику всегда игнорирует. Я говорил что он будет использовать только индексную в данном конкретном случае (мультиколоночная статистика + legacy CE).

(3)
Главный аргумент против этой версии у меня такой: разделитель учёта появился раньше нового CE, при этом SQL Server и в 2008, и в 2012 версиях умудрялся создавать вменяемые планы, правильно оценивая содержимое таблицы. Как видно из содержимого индексной статистики, она в этом никак не помогает.


Потому что в данном конкретном случае из индексной статистики используется не гистограмма, а density vector (опять же, описано по ссылке выше)

(3)
Поэтому всё ещё не вижу смысла целенаправленно пересчитывать индексную статистику по разделителю учёта.


Ну, применительно в разделителю учёта - да, наверное. Но это частный вырожденный случай, а вы в статье рекомендуете вообще все индексные статистики не обслуживать
5. Филин 371 30.09.22 10:39 Сейчас в теме
(4)

Про "полезность"/"бесполезность" - ок, если это важно, действительно СУБД никак не помечает статистики на "полезные" и "не очень". В контексте рассказа эта часть скорее означает следующее: среди всех статистик, которые считывает СУБД, находится все-таки автоматическая статистика, которая (в этом контексте) оказывается самой полезной. Да, вы сейчас скажете про Density Vector индексной статистики - про это будет ниже.

Я говорил что он будет использовать только индексную в данном конкретном случае (мультиколоночная статистика + legacy CE).


Я не поленился, взял первую попавшуюся таблицу - выгрузку из SQL Profiler. Там был определён PK, других индексов не было - я добавил некластерный индекс по полям DatabaseID, SPID (то есть, индекс составной, первое поле одинаково для всех записей - привет типовой от 1С) Включил флаги трассировки 9481 (legacy CE) и 9204 (вывод используемых статистик- нашёл подсказку по вашей ссылке, спасибо!) и 3604 (вывод сообщений в консоль) Всё это на SQL Server 2017 Developer
Выполнил запрос
sel ect top 10 *
fr om query_locks1
where spid > 10
and DatabaseID = 6

В итоге получил такой вывод:
Stats loaded: DbName: test, ObjName: query_locks1, IndexId: 5, ColumnName: SPID, EmptyTable: FALSE

Stats loaded: DbName: test, ObjName: query_locks1, IndexId: 6, ColumnName: DatabaseID, EmptyTable: FALSE


Получается, legacy CE все-таки смотрит на автоматические статистики

Про Density Vector.
Почему я уверен, что в статистике с разделителем учёта он бесполезен? Потому что его значение указывает корреляцию всё так же для одного шага статистики. То есть, классический индекс по Контрагентам: Разделитель, Наименование. В статистике написано: Разделителей - 20 тыс. штук. Разделителей с Наименованием - 18 тыс. штук. Ну и что? Всё равно нет никакой информации, как бьются эти наименования. Я прихожу в эту статистику, спрашиваю "Сколько Наименований будет от А до В" - она говорит - "ну, примерно 18 тыс.". "А от З до К?" - "ну, тоже где-то 18 тыс.". То есть, именно как я говорил - одинаково плохие ответы для одинаково плохих планов. При том, что планы-то получаются явно не такие плохие. Значит, помогает что-то ещё (автостатистики?). И, как я говорил, получались такие планы задолго до 2014 SQL Server.


а вы в статье рекомендуете вообще все индексные статистики не обслуживать

Да, тут я правда разогнался. Весь доклад говорил про статистики с разделителем учёта, а здесь забыл это уточнить. Это правда может сбить с толку, сейчас поправлю. Спасибо, что указали
6. sea123 15 06.10.22 10:37 Сейчас в теме
Подскажите как можно бороться с такой ситуацией:
1. какие то запросы к системе, например, самописный отчет о продажах за период с 06.04-10.04 выполняется мгновенно, но если мы делаем отчет за 05.04-10.04, то отчет уже формируется 50 минут.
2. Проведение документа (реализация товаров, типовые регистры) может подвиснуть и через 20 минут упасть с ошибкой (превышено время ожидания транзакции). При этом на другом компьютере нельзя даже открыть список этих документов, появляется ошибка (превышено время ожидания транзакции)

Лечится только постоянным обновлением статистики (2 раза в день), но это занимает время.
7. Филин 371 06.10.22 11:21 Сейчас в теме
(6) Слишком общие все-таки вопросы. На прошлой работе, где мы специализировались на таких проблемах, я анализировал и сам конкретный запрос, и состояние базы, и что происходило в этот момент в других сессиях. Но тут могу подсказать, куда копать

1. Понятно, что эффективный план существует, но не всегда выбирается. Я бы попытался стабилизировать этот выбор при помощи дополнительных индексов, чтобы у оптимизатора был очевидный способ "правильно" выполнить запрос. Но чтобы подобрать нужный индекс нужно изучить план выполнения запроса

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

Ну и напоследок, решение со статистиками - в целом, правильное, только, похоже, избыточное. Если проблемы частые, то стоит потратить время на поиск и оптимизацию таких "плавающих" запросов.
8. sea123 15 06.10.22 12:03 Сейчас в теме
(7)
2. Не было никого на тот момент в базе. Фоновые задания не выполнялись. Я просто в первый раз в жизни видел такое, чтобы не открывался список документов.
10. Филин 371 10.10.22 01:09 Сейчас в теме
(8) Чтение списков всегда выполняется в Read Uncommitted. Единственное, что может помешать такому чтению - блокировка схемы. Скорее всего в параллельной сессии на СУБД выполнялось перестроение индекса по этому документу: кто-то либо явно запустил команду из Management studio, либо сработал SQL job. И, кстати, если это был динамический SQL при помощи sp_executesql, то блокирующая сессия формально могла быть в контексте другой базы (например, master).
9. 1CUnlimited 320 07.10.22 13:13 Сейчас в теме
Если у вас уже большая база, есть разделитель учёта и очень маленькое регламентное окно и вы уже не успеваете пересчитывать все ваши статистики, тут выбор очень простой. Вы можете просто пропустить все индексные статистики, где используется разделитель учёта. Серьезно. От них нет никакого толку, пересчитывать их не нужно. Я бы еще рекомендовал здесь автоапдейт статистик отключить, чтобы эти автоматические статистики даже стали случайно не пересчитывались.


Вы почемуто старательно обходите рекомендации 1С по флагам трассировки https://its.1c.ru/db/metod8dev#content:5946:hdoc:_top:%D1%82%D1%80%D0%B0%D1%81%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%BA­%D0%B8

Есть замечательный флаг 2731 который уменьшает кардинальность при автоапдейте статистики https://learn.microsoft.com/en-US/sql/relational-databases/statistics/statistics?view=sql-server-2017#auto_update_statistics-option и на 2014 SQL он по умолчанию не включен.
Этот флаг позволяет вообще забыть о ночных пересчетах статистики и ликвидирует напр такие явления
1) Пересчитали проводки по 3 миллионам операций
2) отчеты за последий день стали работать медленно (статистика не автообновилась из за недостаточно количества измененных записей для автоапдейта )
Только с флагом 2731 можно жить на 5 терабайтных базах, где процессы идут почти круглосуточно

P S Сам экскурс в работу статистики интересен, и еще один камень в огород разделителей учета. Но несмотря на все статистики и индексы MS SQL не может сам сделать соединения более эффективными без доп условий запросов о чем я тут писал https://infostart.ru/1c/articles/1730020/
Те. получается ему правильный план нужно подсказывать особой структурой запроса
11. Филин 371 10.10.22 01:18 Сейчас в теме
(9) У меня кардинально противоположное отношение к автообновлению статистик. Подробно я про это рассказывал здесь https://infostart.ru/1c/articles/1267307/ (примерно с середины доклада) Если кратко: автообновление совершенно непредсказуемо, оно будет включаться когда захочет (а в условиях хайлода это почти всегда означает "когда всем неудобно"). Поэтому надёжнее самому своими скриптами следить за состоянием статистик - хотябы заранее знаешь, в какое время будет нагрузка и возможны блокировки.

Ну и, если честно, я считаю, что оптимизатор запросов у MS SQL Server - один из лучших на рынке. Понятно, что он не может всегда справляться идеально и есть сценарии, когда его можно "подопнуть" в нужном направлении. Но с другой стороны - если вы заранее знаете что-то важное о своих данных (нужный диапазон дат или группу в справочнике) - почему бы действительно не поделиться этим знанием с СУБД в виде дополнительного условия?
То есть, я согласен с вашим случаем, когда доп. условие помогает ускорить запрос. Но это не означает, что оптимизатор у MS SQL совершенный бездарь - он отлично справляется со своей работой в большинстве случаев.
Оставьте свое сообщение