Мониторинг SQL Server с помощью Extended Events (и не только) для 1С. Как держать руку на пульсе?

Публикация № 1056294

Администрирование - Производительность и оптимизация (HighLoad)

SQL Server Profiler Exteded Events мониторинг производительность

193
Что и как мониторить в работе SQL Server, чтобы держать Вашу систему в форме.

Немного истории

Как показывает практика, во многих компаниях малого и среднего бизнеса (а иногда и крупного) можно столкнуться с отсутствием должного обслуживания серверов баз данных. В самом крайнем случае это выражается в наличии неэффективной стратегии бэкапирования или, о ужас, ее полном отсутствии! Представьте, что произойдет, если после аварии не удастся восстановить базу со всеми данными о деятельности компании?

Приходилось ли Вам сталкиваться с системными администраторами, которые в случае проблем производительности и стабильности баз 1С отвечают:

  • Это не наша проблема! Обращайтесь к разработчикам 1С.
  • С нашей стороны все в порядке, это 1С так работает.
  • Какая еще 1С? Мне нужно настроить AD, а также провести миграцию некоторых серверов в облака.
  • (просто молча убегают в закат) и др. странные ситуации.

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

Разработчики 1С также не всегда имеют необходимые компетенции и получается замкнутый круг. Разработчики показывают пальцем на админа, а админ на "этих" 1Сников. Причем у разработчиков даже прав доступа может не быть для решения проблем. В итоге бизнес заказывает внешний аудит производительности :)

Как тут быть? Все просто (ну, почти) - нужно кооперироваться. Можно настроить мониторинг на SQL Server силами админа, а результаты показывать разработчикам 1С и обсуждать что нужно для решения проблем. Согласитесь, сесть раз в неделю или раз в месяц и разобрать проблемы - займет намного меньше сил и нервов, если продолжать спихивать друг на друга ответственность и конфликтовать. * Конечно, это работает только при адекватности всех сторон.

Сегодня в статье мы рассмотрим простые способы настройки мониторинга SQL Server с помощью Extended Events и с некоторыми другими способами, а также продемонстрируем как собранные данные интерпретировать и что показать 1Сникам. 

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

Extended Events vs. SQL Profiler (SQL Trace)

Прежде чем перейти непосредственно к примерам настроек сбора данных, нужно пояснить почему все же предлагается использовать Extended Events вместо SQL Profiler. Несомненно, SQL Profiler остается одним из самых используемых инструментов для диагностики работы SQL Server, несмотря на то, что считается устаревшим. Не зря Microsoft предупреждает, что он может быть удален в будущих версиях СУБД, ведь ему на смену давно пришел более продвинутый инструмент - Extended Events.

SQL Profiler является графической надстройкой для SQL Trace, с помощью которой он собирает данные, а после выводит их в графический интерфейс приложения. Как и SQL Profiler, SQL Trace считается устаревшим инструментом и может быть удален в будущем. Так почему же расширенные события лучше старых добрых трасс?

  1. SQL Trace находится в режиме поддержки и не дополняется новым функционалом. Также он изначально содержал меньше доступных событий для анализа. К тому же, Extended Events содержит больше информации о событиях. Сравните возможности SQL Trace и Extended Events для различных редакций SQL Server по количеству доступных событий.
  2. Значительно меньшее влияние на производительность при включенном сборе данных, причем имеются расширенные настройки, с помощью которых на это можно влиять.
  3. Настройки сбора данных (события, фильтры и др.) можно менять на активных сессиях, прямо во время сбора данных.
  4. Доступен хэш запросов, чтобы идентифицировать одинаковые тексты запросов.
  5. Можно настроить различные способы хранения логов, причем одновременно в нескольких вариантах.
  6. Встроенные инструменты в SQL Server Managment Studio и инструкции TSQL для работы с ними.
  7. Поддержка PowerShell :)
  8. И еще многое другое.

Все еще используйте SQL Profiler / SQL Trace? Я тоже! Но, SQL Profiler только для тестовых баз, где нужно быстро посмотреть, что там за запрос. Если же нужно выполнять работы на рабочем окружении или настраивать мониторинг, то только Extended Events!

Собираем данные

И так, Вы собираетесь использовать расширенные события, но куда смотреть? В SQL Server Managment Studio в разделе "Управление -> Расширенные события -> Сеансы" Вы можете найти список всех сеансов расширенных событий.

Здесь же можно добавить новый сеанс расширенных событий с помощью мастера, так и с помощью полной настройки вручную с нуля. Также можно управлять состоянием каждого сеанса (остановить или запустить), удалить его или сформировать скрипт T-SQL на основе существующего объекта.

Рассматривать процесс создания сеанса с помощью графического интерфейса мы не будем. Вместо этого создадим основные сеансы расширенных событий с помощью T-SQL.

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

Тяжелые запросы по CPU

Обычно всех интересуют долгие по времени выполнения запросы, или запросы отбирающие больше всего ресурсов CPU. Это не одно и то же, ведь на сервере может быть включен параллелизм, тогда затраченное процессорное время не будет равно времени выполнения запроса даже приблизительно. Для отслеживания событий по CPU достаточно использовать два события: RPC:Completed и SQL:BatchCompleted. Первое событие возникает при вызове процедур, которые обычно делает платформа 1С через обращение к sp_executesql. Практически во всех остальных случаях это второе событие выполнения пакета запросов.

Также стоит учитывать, чтоб сбор абсолютно всех запросов особо смысла не имеет и их нужно отфильтровать от "шума". Для этого можно установить фильтр по полю времени выполнения события (поле "duration"). Значения там хранятся в микросекундах. Обычно я собираю запросы, которые выполняются более 5 секунд (то есть более 5000000 микросекунд).

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

 
 Сбор тяжелых запросов по CPU

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

Тяжелые запросы по объему данных

На втором месте для поиска тяжелых запросов используется объем логических чтений. Именно логических. То есть тех, которые были выполнены из оперативной памяти. Это важно, т.к. SQL Server кэширует страницы, полученные с диска в буферный кэш, то есть в оперативную память. Именно поэтому SQL Server такой прожорливый в части использования RAM (особенно если его не ограничить в настройках инстанса), но зато позволяет значительно повысить производительность. Тут главное соблюдать баланс.

Сбор тяжелых запросов по логическим чтениям позволит определить те запросы, которые чаще всего используют буферный кэш, тем самым "вымывая" из него данные для других запросов. Что это значит? Допустим, на сервере 32 ГБ оперативной памяти. Бухгалтер запустил отчет, запрос которого благодаря усилиями разработчика, считал 25 ГБ данных. Тем самым весь буфферный кэш SQL Server теперь используется этим отчетом, а остальные запросы будут вынуждены обращаться к диску и заново получать страницы, помещать их в кэш. Фактически, пользователи столкнуться с замедлением работы информационной системы. Описание, конечно, общее, но смысл должен быть понятен.

Собирать будем те же события, что и для CPU: RPC:Completed и SQL:BatchCompleted. Для избавления от избыточного логирования событий в этом случае необходимо поставить фильтр на поле с размером прочитанных данных (то есть "logical reads"). На практике все зависит от конкретной системы и размера базы. Обычно использую значение фильтра от 10000 до 50000 прочитанных страниц (то есть от ~80 МБ до ~400 МБ, т.к. 1 страница = 8 КБ).

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

 
  Сбор тяжелых запросов по объему чтения

В итоге будем иметь статистику какие запросы у нас "прожорливые" по чтению.

Анализ блокировок и взаимоблокировок

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

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

 
 Сбор информации о таймаутах на блокировках

Для сбора и последующего анализа причин взаимоблокировок можно использовать сессию, в которой собираются данные событий Lock:Deadlock, Lock:Deadlock Chain и "XML Deadlock Report" для построения графического отчета.

 
 Сбор информации о взаимоблокировках

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

Ошибки, ошибки, ошибки

Было бы не плохо также отслеживать любые ошибки, происходящие на уровне СУБД. Для этого воспользуемся скриптом для сбора всех ошибок с помощью события "SQL:ErrorReported".

 
 Сбор информации об ошибках

Может пригодиться для диагностики не только проблем SQL Server, но и ошибок при выполнении запросов платформой 1С.

Какой у нас план?

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

Поэтому лучше использовать такие пути получения плана запроса:

  1. Посмотреть предполагаемый план запроса для активных операций. Если Вы знаете, что сейчас в базе выполняется проблемная операция, то выполните этот скрипт и посмотрите ее план.
  2. Найти план выполнения по тексту запроса, если он еще содержится в кэше. Вот пример скрипта.
  3. Собирать все планы выполнения и повесить сервер с помощью Extended Events. Серьезно! Это только для ознакомления и применяется в редких случаях, особенно на продакшене.

Есть и другие способы получить план. Вот дополнительная информация по этому поводу.

Теперь, когда у Вас есть план запроса, Вы можете составить свой план работ! :).

Анализируй это!

Собрать данные недостаточно, их еще нужно проанализировать! И тут платформа 1С приготовила нам некоторые сюрпризы. Разберем пример сбора и анализа данных собранных тяжелых запросов по CPU, а также анализ событий по таймаутам на блокировках. Все примеры будут очень похожи.

Перенос в отдельную базу данных

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

 
 Останавливаем сессию расширенных событий

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

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

 
 Перенос данных расширенных событий в отдельную базу

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

 
 Работа с XEL без сохранения в базу

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

-- Добавляем уникальное поле ID для каждой записи
ALTER TABLE [dbo].[QueryAnalysis] ADD ID INT IDENTITY(1,1);

-- Изменяем тип колонки "database_name" с "nvarchar(max)" на "nvarchar(150)",
-- чтобы его можно было использовать в индексах
ALTER TABLE [dbo].[QueryAnalysis] ALTER COLUMN [database_name] nvarchar(150) NOT NULL;

-- Добавляем кластерный индекс по периоду, имени базы и ключу записи
CREATE UNIQUE CLUSTERED INDEX CIX_Timestamp_DatabaseName_ID ON [dbo].[QueryAnalysis] 
(
	[timestamp (UTC)], 
	[database_name], 
	[ID]
);

-- Добавляем индекс для быстрого поиска по "ID" + "timestamp (UTC)".
-- Для оптимизации включены покрывающие поля, которые содержат тексты запросов, 
-- но это приводит к увеличению размера базы с логами.
CREATE UNIQUE NONCLUSTERED INDEX [UI_ID_Timestamp] ON [dbo].[QueryAnalysis]
(
	[ID] ASC,
	[timestamp (UTC)] ASC
)
INCLUDE ( 	
	[batch_text],
	[sql_text],
	[database_name],
	[statement]
);

-- Если есть возможность, то можно включить сжатие PAGE на уровне таблиц и индексов для базы с логами.
-- Так можно значительно сэкономить место.

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

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

Эти действия могут отличаться, если состав собираемых полей с помощью Extended Events другой, но общий принцип должен быть понятен. Финальный вариант таблицы с логами выглядит так.

Осталось решить проблему постобработки данных.

Постобработка. Или грабли от 1С

Для SQL-запросов платформы есть одна большая особенность (другие мелкие нюансы можно не рассматривать): имена временных таблиц в запросах могут иметь случайные имена вида "#tt<Тут случайны номер, который присвоит платформа 1С>". Аналогично обстоят дела и с именами параметров: @P1, @P2 ... @PN.

Поэтому было бы не плохо привести их имена к общему виду. Например, к "#ttN" для временных таблиц и @PN для имен параметров.

 
 Постобработка запросов

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

Смотрим результаты

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

 
 Анализ запросов по CPU и чтениям

Собранные логи по блокировкам также можно изучить запросом

 
 Анализ блокировок

И напоследок посмотрим ошибки SQL Server.

 
 Смотрим ошибки

Запросы можно адаптировать под свои настройки расширенных событий.

А как же технологический журнал?

Конечно, использовать технологический журнал можно для анализа тяжелых запросов и блокировок, даже планы запроса можно собрать. Но вот незадача! Влияние ТЖ на производительность системы может быть на столько высоко, что фактически остановит основную работу. Именно поэтому встроенные средства SQL Server намного лучше для диагностики проблем на уровне СУБД.

Но, к сожалению, без технологического журнала все равно не обойтись. Вместе с простым мониторингом SQL Server он поможет решать такие задачи:

 
 1. Поиск мест в модулях конфигурации, откуда выполняется запрос
 
 2. Поиск ошибок, связанных с работой СУБД

Это только те задачи, которые можно решить с минимальной затратой ресурсов. В статье мы не будем подробно останавливаться на работе ТЖ, но с его помощью можно решить множество других вопросов, с которыми Extended Events не в силах помочь:

  • Анализ и поиск проблем с управляемыми блокировками.
  • Поиск узких мест производительности в коде конфигураций.
  • Проверка работы сервера, кластера.
  • И многое другое. 

То есть без технологического журнала все равно никуда, но для диагностики проблем СУБД лучше использовать нативные инструменты.

Что еще можно / нужно собирать

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

  • С помощью счетчиков производительности ОС Windows:
    • Загрузку оборудования
    • Внутренние показатели SQL Server.
  • Статистику обслуживания базы данных:
    • Один и более раз в день сохранять информацию о состоянии индексов в базу данных с логами с помощью Job'а или другим способом. Можно использовать этот скрипт.
    • Сохранять информацию о состоянии статистик в базу с логами также один или несколько раз в сутки. Например, этим скриптом.
    • Фиксировать операции обслуживания индексов и статистик. Например, в этом скрипте обслуживания выделено место, где эту информацию можно записывать в базу (имя таблицы, имя обслуживаемого объекта, тип операции, дата запуска и дата завершения).
  • Другую необходимую информацию:

Конечный вариант собираемых данных полностью зависит от целей мониторинга и должен быть адаптирован под Вашу ситуацию.

Конечно, можно использовать стандартные средства Windows и SQL Server, но можно взять в помощь какую-либо систему мониторинга. Например, Zabbix, или вообще все логи выгружать в ElasticSearch. Тут все зависит от потребностей.

Уровень Enterprise!

Вы дочитали до сюда с вопросом "А проще нельзя сделать"? Конечно, можно! Если бы выполнять мониторинг приходилось всегда через подобную ручную работу, то реагировать на проблемы производительности не всегда бы удавалось. Тем более на больших, высоконагруженных системах. Тут на помощь приходят инструменты мониторинга:

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

Конечно, весь мониторинг можно организовать самостоятельно, но на это уйдет гораздо больше времени, а про сопровождение вообще лучше не говорить :). Есть чем дополнить список и знаете еще достойные инструменты? Ждем в комментариях!

Это еще не все

Мы рассмотрели преимущества использования Extended Events для диагностики работы СУБД и некоторые нюансы в контексте платформы 1С. Кратко пробежались по некоторым приемам работы с технологическим журналом и другим направлениям развития мониторинга.

Главное, что нужно понять, так это существующий большой разрыв в инструментах диагностики платформы 1С и SQL Server, причем не в пользу первой. Конечно, без ТЖ никуда, но для мониторинга СУБД и оперативной диагностики запросов, блокировок, взаимоблокировок и ошибок лучше использовать собственные инструменты SQL Server.

Другие ссылки

193

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. acanta 64 05.05.19 13:32 Сейчас в теме
Спасибо за статью. Встречался вопрос на форуме про заполнение диска при настроенном ТЖ.
Подскажите пожалуйста, размеры и хранение файлов расширенных событий тоже где то настраиваются?
YPermitin; +1 Ответить
2. YPermitin 4045 05.05.19 13:36 Сейчас в теме
(1) конечно!

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

В статье в скриптах указаны параметры хранения и комментарии к ним.

Есть еще дополнительные настройки по хранению логов, но там уже специфика.
Созинов; acanta; +2 Ответить
3. 3vs 06.05.19 05:57 Сейчас в теме
Юрий - круто!
Моё только начало, узнаю себя в пунктах 1,2, 4, третий у меня не используется. :-)
YPermitin; +1 Ответить
4. YPermitin 4045 06.05.19 06:36 Сейчас в теме
(3) спасибо!

Хорошо, когда СУБДшные блокировки - не проблема :)
5. 3vs 06.05.19 07:23 Сейчас в теме
(4)Да, меня с моими базами это особо не касается.
Зато человечеству есть куда стремиться! :-)
YPermitin; +1 Ответить
6. Dach 275 06.05.19 09:43 Сейчас в теме
Классная статья!

А есть опыт использования сбора данных по тяжелым запросам в продуктиве? Не замедляет ли это работу сервера? Как настроить так, чтобы минимально влияло?
8. YPermitin 4045 06.05.19 10:01 Сейчас в теме
(6) первый и второй вариант сесии по CPU и чтениям можно спокойно запускать в проде. То же можно сделать и для сесии по взаимоблокировкам.

Если фильтр нужно ужесточить, это если тяжелых запросов ну очень много и нужно уменьшить объем собираемых данных, то в фильтрах можно увеличить минимальное время выполнения с 5 до 10 сек и выше, а чтений с 50000 до 100000. Но я такое практически не делал, предложенные сесии достатчно хорошо отрабатывают.

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

И все будет ОК:)
Созинов; +1 Ответить
7. nvv1970 06.05.19 09:48 Сейчас в теме
Мощная методичка вышла!
Толково, ёмко, по делу!
Однозначно - "зорка"!
YPermitin; +1 Ответить
9. Andrefan 06.05.19 11:26 Сейчас в теме
Добрый день. Всю жизнь думал, что в SQL Server 2008 нет расширенных событий. У меня Microsoft SQL Server 2008 R2 (SP3), но в том месте, где в более старших версиях есть эта ветка, у меня она отсутствует. Действительно ли есть в 2008 скуле этот механизм? если да, то где его найти, или как добавить (что доустановить)?
10. YPermitin 4045 06.05.19 11:34 Сейчас в теме
(9) все так, в 2008 они есть, вот только нет удобного UI для работы. Все только через T-SQL.

Вроде есть старания сообщества на эту тему, но сам не пробовал: https://archive.codeplex.com/?p=extendedeventmanager

Сам я и для новых редакций SQL Server графический интерфейс почти не использую. Только T-SQL, только хардкор! :)
11. Painted 28 06.05.19 14:23 Сейчас в теме
Эти же данные можно собрать из DMV типа sys.dm_exec_query_stats.
YPermitin; +1 Ответить
12. YPermitin 4045 06.05.19 14:40 Сейчас в теме
(11) и да и нет. Там содержится только кэшированные данные, которые со временем очищаются.

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

Чем выше нагрузка на кэш, тем больше данных статистики не будут учтены.
13. Артано 658 08.05.19 07:10 Сейчас в теме
Очень хорошая статья, мне понравилось. Но я бы не стал задвигать в дальний угол статистику ожиданий. По своему личному опыту, я с анализа статистики ожиданий и начинаю изучение проблем производительности. И только потом уже принимаю решение что смотреть дальше. Хотя, возможно, более опытные товарищи как в SQL так и в педагогике, меня поправят или уточнят.
Созинов; Dach; YPermitin; +3 Ответить
14. YPermitin 4045 08.05.19 07:12 Сейчас в теме
(13) все так, просто здесь упор сделан на Extended Events. А так согласен, обычно сам так и поступаю, если впервые сталкиваюсь с сервером БД / системой.

Так что поправлять нечего :) Истину говорите :)))
15. Painted 28 15.05.19 15:41 Сейчас в теме
Установил сбор тяжелых запросов, эвенты забиты сбором статистики. Встречаются и рабочие запросы от 1С, но редко, как крупинки золота и тяжело искать.
16. YPermitin 4045 15.05.19 15:44 Сейчас в теме
(15) не понятно что Вы настроили.

Проверьте какие события собирабтся, фильтры и т.д.
17. Painted 28 15.05.19 15:50 Сейчас в теме
Таких событий много. Можно их отфильтровать?
Прикрепленные файлы:
18. YPermitin 4045 15.05.19 15:55 Сейчас в теме
(17) это операции обслуживания и, конечно, они тяжелые. На скриншоте видно, что они выполняются ночью.

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

Но я бы просто рекомендовал потом в запросе сделать отбор только по рабочему времени. Ночью, как видно, никто особо не работает.
19. Hatson 335 28.06.19 14:28 Сейчас в теме
Офигенная винрарная статья! Аплодирую стоя!
YPermitin; +1 Ответить
20. YPermitin 4045 28.06.19 14:54 Сейчас в теме
21. NNomad 30.08.19 16:42 Сейчас в теме
Жаль, что в SQL server 2008 R2 отсутствует SQL:BatchCompleted. А так хотелось помониторить запросы.
22. AndyPLsql 20.09.19 10:54 Сейчас в теме
(21)
SQL:BatchCompleted

Куда же она у вас делась? У всех есть.
Оставьте свое сообщение