Этот материал был создан при поддержке и спонсорстве компании iBase.ru, которая разрабатывает HQbird и инструменты Firebird SQL для предприятий и предоставляет сервис технической поддержки для Firebird SQL.
Материал выпущен под лицензией Public Documentation License https://www.firebirdsql.org/file/documentation/html/en/licenses/pdl/public-documentation-license.html
Все части
- Что Нового в Firebird 5.0. Часть 1: Оптимизатор - в формате pdf
- Что Нового в Firebird 5.0, Часть 2: SQLs - в формате pdf
- Что нового в Firebird 5.0, Часть 3: SKIP LOCKED - в формате pdf
- Что нового в Firebird 5.0. Часть 4. Параллельные возможности бэкап/рестор/sweep/сздание индекса - в формате PDF
- Что нового в Firebird 5.0. Часть 5.Кеш подготовленных запросов, сжатие данных и другие улучшения
- Что нового в Firebird 5.0. Часть 6. Профилирование SQL запросов - скоро!
- Параллельное чтение данных в Firebird - статья Д.Симонов, В.Хорсун
Предисловие
Недавно вышел релиз Firebird 5.0. Это восьмой основной выпуск СУБД Firebird, разработка которого началась в мае 2021 года.
В Firebird 5.0 команда разработчиков сосредоточила свои усилия на повышение производительности СУБД в различных аспектах, таких как:
-
параллельное выполнение для распространённых задач: backup, restore, sweep, создание и перестроение индекса;
-
улучшение масштабирования в многопользовательской среде;
-
ускорение повторной подготовки запросов (кеш компилированных запросов);
-
улучшение оптимизатора;
-
улучшение алгоритма сжатия записей;
-
поиск узких мест с помощью плагина профилирования.
Поскольку объём материала довольно большой, то я разделю описание новых функций на несколько частей:
-
улучшение в оптимизаторе запросов;
-
новые возможности в языке SQL Firebird 5.0;
-
параллелизм и другие функции появившиеся в Firebird 5.0;
-
поиск узких места с помощью плагина PSQL профилирования.
В прошлых частях я рассказал о новых возможностях языка SQL и улучшениях оптимизатора. Теперь я расскажу о параллельном выполнении административных задач в Firebird 5.0.
1. Параллельное выполнение задач
Начиная с версии 5.0 Firebird может выполнять некоторые задачи, используя несколько потоков параллельно. Часть этих задач использует параллелизм на уровне ядра Firebird, другие реализованы непосредственно в утилитах. В настоящее время на уровне ядра реализовано параллельное выполнение задач очистки (sweep) и создания индекса. Параллельное выполнение поддерживается как для автоматической, так и для ручной очистки (sweep).
В следующих версиях планируется добавить параллелизм при выполнении SQL запроса.
1.1. Параллельное выполнение задач в ядре Firebird
Для обработки задачи с несколькими потоками движок Firebird запускает дополнительные рабочие потоки и создает внутренние рабочие соединения. По умолчанию параллельное выполнение отключено. Существует два способа включить параллелизм в пользовательском соединении:
-
Установить количество параллельных рабочих процессов в DPB, используя тег
isc_dpb_parallel_workers
; -
Установить количество параллельных рабочих процессов по умолчанию с помощью параметра
ParallelWorkers
вfirebird.conf
.
Некоторые утилиты (gfix
, gbak
) поставляемые с Firebird имеют ключ командной строки -parallel
для установки количества параллельных рабочих процессов. Зачастую этот переключатель просто передаёт количество рабочих процессов через тег isc_dpb_parallel_workers
при соединении с базой данных.
Новый параметр ParallelWorkers
в firebird.conf
устанавливает количество параллельных рабочих процессов по умолчанию, которые могут использоваться любым пользовательским соединением, выполняющим распараллеливаемую задачу. Значение по умолчанию равно 1 и означает отсутствие использования дополнительных параллельных рабочих процессов. Значение в DPB имеет более высокий приоритет, чем значение в firebird.conf
.
Для контроля количества дополнительных рабочих процессов (workers), которые может создать движок, в firebird.conf
есть две новые настройки:
- ParallelWorkers
-
Устанавливает количество параллельных рабочих процессов по умолчанию, используемых пользовательскими соединениями. Может быть переопределено для соединения путем использованием тега
isc_dpb_parallel_workers
в DPB. - MaxParallelWorkers
-
Ограничивает максимальное количество одновременно используемых рабочих процессов для данной базы данных и процесса Firebird.
Внутренние рабочие соединения создаются и управляются самим движком Firebird. Движок поддерживает пулы рабочих соединений для каждой базы данных. Количество потоков в каждом пуле ограничено значением параметра MaxParallelWorkers
. Пулы создаются каждым процессом Firebird независимо.
В архитектуре SuperServer рабочие соединения реализованы как облегченные системные соединения, а в Classic и SuperClassic они выглядят как обычные пользовательские соединения. Все рабочие соединения автоматически создаются сервером при необходимости. Таким образом, в классических архитектурах нет дополнительных серверных процессов. Дополнительные рабочие соединения присутствуют в таблицах мониторинга. Неработающие рабочие соединения уничтожаются через 60 секунд бездействия. Кроме того, в классических архитектурах рабочие соединения уничтожаются сразу после того, как последнее пользовательское соединение отключается от базы данных.
1.1.1. Практические рекомендации по установке параметров
Параметр MaxParallelWorkers
позволяет администраторам ограничить максимальное количество одновременно используемых рабочих процессов. Это может полезно для того, чтобы администратор запуская свои задачи был ограничен в "аппетитах". Он может указать слишком большое значение в переключателе -parallel
, и мешать другим пользователям работать с базой данных, создавая излишнюю нагрузку.
Для архитектуры SuperServer я рекомендую ставить значения параметра MaxParallelWorkers
равным количеству физических ядер вашего процессора (или всех процессоров) или установить равным 64 (максимальное значение). Для классической архитектуры MaxParallelWorkers
надо ставить меньшим равным количеству физических ядер вашего процессора (мы рекомендуем ставить половину от общего количества ядер). В архитектуре Classic ограничение MaxParallelWorkers
работает для каждого процесса.
Значение параметра ParallelWorkers
должно быть меньшим или равным значению MaxParallelWorkers
. У вас может возникнуть соблазн установить ParallelWorkers = MaxParallelWorkers
, но в этом случае надо учитывать, что вы работаете с базой данных не один. Кроме того, если у вас включен автоматических sweep, то при старте он заберёт почти все ресурсы у других работающих клиентский соединений. Лучше установить ParallelWorkers
не более половины от MaxParallelWorkers
, а при необходимости переопределять число рабочих потоков через isc_dpb_parallel_workers
или переключатель -parallel
в утилитах.
Все зависит от того, делается это под нагрузкой или нет. Если я восстанавливаю базу данных, то в этот момент с ней точно никто не работает, поэтому я могу запросить максимум параллельных потоков. А вот если вы делаете backup, sweep или создание индекса под рабочей нагрузкой, то вам нужно умерить свои аппетиты. |
Далее я покажу как параллелизм влияет на время построения или перестроения индекса. Влияние параллелизма на автоматический sweep показано не будет, поскольку она стартует автоматически без нашего участия. Влияние параллелизма на ручной sweep будет продемонстрировано при рассмотрении выполнения задач утилитами Firebird.
1.1.2. Параллелизм при создании или перестройке индекса
Параллелизм может быть использован при создании или перестроении индексов.
Сравним скорость при создании индекса для таблицы WORD_DICTIONARY
, содержащей 4079052 записей. Для чистоты эксперимента перед новым тестом перезагружаем службу Firebird. Кроме того, для того чтобы таблица была в страничном кеше выполняем
SELECT COUNT(*) FROM WORD_DICTIONARY;
Как известно построение индекса всегда происходит по COMMIT. В примерах я не даю команду |
Запрос для создания индекса выглядит следующим образом:
CREATE INDEX IDX_WORD_DICTIONARY_NAME ON WORD_DICTIONARY (NAME);
Статистика выполнения этого запроса с ParallelWorkers = 1
выглядит следующим образом:
Current memory = 2577810256 Delta memory = 310720 Max memory = 3930465024 Elapsed time = 6.798 sec Buffers = 153600 Reads = 11 Writes = 2273 Fetches = 4347093
Теперь удалим этот индекс, установим в конфиге ParallelWorkers = 4
и MaxParallelWorkers = 4
и перезапустим сервер. Статистика для выполнения того же запроса выглядит так:
Current memory = 2580355968 Delta memory = 2856432 Max memory = 4157427072 Elapsed time = 3.175 sec Buffers = 153600 Reads = 11 Writes = 2277 Fetches = 4142838
Как видите время создания индекса уменьшилось в 2 с небольшим раза.
Тоже самое происходит при перестроении индекса запросом:
ALTER INDEX IDX_WORD_DICTIONARY_NAME ACTIVE;
1.2. Параллельное выполнение задач утилитами Firebird
Некоторые утилиты (gfix
, gbak
) поставляемые с Firebird тоже поддерживает параллельное выполнение задачи. Они используют количество параллельных рабочих процессов установленное в параметре ParallelWorkers
в firebird.conf
. Количество параллельных рабочих процессов можно переопределить используя ключ командной строки -parallel
.
Я рекомендую всегда устанавливать количество параллельных процессов явно через переключатель -parallel
или -par
.
Параллелизм в утилитах Firebird поддерживается для следующих задач:
-
Создание резервной копии с помощью утилиты
gbak
-
Восстановление из резервной копии с помощью утилиты
gbak
-
Ручной sweep с помощью утилиты
gfix
-
Обновление icu с помощью утилиты
gfix
1.2.1. Параллелизм при выполнении резервного копирования с помощью утилиты gbak
Давайте посмотрим как параллелизм влияет на резервное копирование утилитой gbak
. Естественно я буду использовать самый быстрый вариант резервного копирования через менеджер сервисов и с отключенной сборкой мусора. Для того чтобы можно было отследить время каждой операции во время резервного копирования добавим переключатель -stat td
.
Сначала запустим резервное копирования без параллелизма:
gbak -b -g -par 1 "c:\fbdata\db.fdb" "d:\fbdata\db.fbk" -se localhost/3055:service_mgr -user SYSDBA -pas masterkey -stat td -v -Y "d:\fbdata\5.0\backup.log"
Резервное копирование завершилось за 35.810 секунд.
А теперь попробуем запустить резервное копирование с использованием 4 потоков.
gbak -b -g -par 4 "c:\fbdata\db.fdb" "d:\fbdata\db.fbk" -se localhost/3055:service_mgr -user SYSDBA -pas masterkey -stat td -v -Y "d:\fbdata\5.0\backup-4.log"
Резервное копирование завершилось за 18.267 секунд.
Как видите при увеличении количества параллельных обработчиков скорость резервного копирования растёт, хотя и не линейно.
На самом деле влияние параллельных потоков на скорость резервного копирования зависит от вашего железа. Оптимальное число параллельных потоков следует подбирать экспериментально. Любые дополнительные переключатели тоже могут изменить картину. Так например переключатель |
1.2.2. Параллелизм при выполнении восстановления из резервной копировании с помощью утилиты gbak
Теперь давайте посмотрим как параллелизм влияет на скорость восстановления из резервной копии. Восстановление из резервной копии состоит из следующих этапов:
-
создании базы данных с соответствующей ODS;
-
восстановление метаданных из резервной копии;
-
восстановлении данных пользовательских таблиц;
-
построение индексов.
Параллелизм будет задействован только на двух последних этапах.
Для того чтобы можно было отследить время каждой операции во время восстановления из резервной копии добавим переключатель -stat td
.
Сначала запустим восстановление из резервной копии без параллелизма:
gbak -c -par 1 "d:\fbdata\db.fbk" "c:\fbdata\db.fdb" -se localhost/3055:service_mgr -user SYSDBA -pas masterkey -v -stat td -Y "d:\fbdata\restore.log"
Восстановление из резервной копии завершилось за 201.590 секунд. Из них 70.73 секунды ушло на восстановление данных таблиц и 121.142 секунды на построение индексов.
А теперь попробуем запустить восстановление из резервной копии с использованием 4 потоков.
gbak -c -par 4 "d:\fbdata\db.fbk" "c:\fbdata\db.fdb" -se localhost/3055:service_mgr -user SYSDBA -pas masterkey -v -stat td -Y "d:\fbdata\restore-4.log"
Восстановление из резервной копии завершилось за 116.718 секунд. Из них 26.748 секунды ушло на восстановление данных таблиц и 86.075 секунды на построение индексов.
С помощью 4 параллельных рабочих нам удалось увеличить скорость восстановления почти в два раза. При этом скорость восстановления данных выросла почти в 3 раза, а построение индексов ускорилось в 1.5 раза.
Это объясняется довольно просто, индексы не восстанавливаются параллельно, параллелизм используется только при построении больших индексов. Справочные таблицы обычно небольшие, индексы на них маленькие, а количество таких таблиц может быть большим. Поэтому на вашей базе данных цифры могут быть другими.
Обратите внимание на то, что параметр |
1.2.3. Параллельный ручной sweep с помощью утилиты gfix
sweep (чистка) - это важный процесс обслуживания: Firebird сканирует базу данных, и если в ней присутствуют "мусорные" версии записей удаляет их со страниц данных и из индексов. Основная цель запуска sweep - это подвинуть "вверх" номер Oldest Interesting Transaction (Oldest transaction в gstat -h).
До Firebird 3.0 sweep всегда сканировал все страницы данных. Однако начиная с Firebird 3.0 (ODS 12.0) на страницах данных (DP) и на страницах указателей на страницы данных (PP) есть специальный swept flag, который устанавливается в 1, если sweep уже просмотрел страницу данных и вычистил с неё мусор. При первой модификации записей на этот таблице флаг снова сбрасывается в 0. Начиная с Firebird 3.0 автоматический и ручной sweep пропускает страницы у которых swept флаг равен 1. Поэтому повторный sweep будет проходить намного быстрее, если конечно с момента предыдущего sweep вы не успели поменять записи на всех страницах данных базы данных. Новые страницы данных всегда создаются с swept flag = 0. При восстановлении базы данных и резервной копии все страницы DP и PP будут с swept flag = 0. |
Как правильно тестировать? Холостой sweep после восстановления из резервной копии не дал разницы в однопоточном и многопоточном режиме. Поэтому я сначала провёл на восстановленной БД sweep для того, чтобы следующий sweep не проверял незамусоренные страницы, а потом сделал запрос вроде такого:
update bigtable set field=field;
rollback;
exit;
Целью этого запроса было создания мусора в базе данных. Теперь можно запускать sweep для тестирования скорости его выполнения.
Сначала запустим sweep без параллелизма:
gfix -user SYSDBA -password masterkey -sweep -par 1 inet://localhost:3055/mydb
DESKTOP-E3INAFT Sun Oct 22 16:24:21 2023 Sweep is started by SYSDBA Database "mydb" OIT 694, OAT 695, OST 695, Next 696 DESKTOP-E3INAFT Sun Oct 22 16:24:42 2023 Sweep is finished Database "mydb" 1 workers, time 20.642 sec OIT 696, OAT 695, OST 695, Next 697
Теперь снова делаем обновление большой таблицы и rollback, и запустим sweep с 4 параллельным рабочими.
gfix -user SYSDBA -password masterkey -sweep -par 4 inet://localhost:3055/mydb
DESKTOP-E3INAFT Sun Oct 22 16:26:56 2023 Sweep is started by SYSDBA Database "mydb" OIT 697, OAT 698, OST 698, Next 699 DESKTOP-E3INAFT Sun Oct 22 16:27:06 2023 Sweep is finished Database "mydb" 4 workers, time 9.406 sec OIT 699, OAT 702, OST 701, Next 703
Как видите скорость выполнения sweep выросла в 2 с лишним раза.
1.2.4. Параллельное обновление icu с помощью утилиты gfix
Переключатель -icu
позволяет перестроить индексы в базе данных с использованием нового ICU.
Дело в том, что библиотека ICU используется Firebird для поддержки COLLATION для многобайтных кодировок вроде UTF8. В Windows ICU всегда поставляется в комплекте с Firebird. В Linux же ICU обычно является системной библиотекой. При переносе файла базы данных с одного дистрибутива Linux на другой, ICU установленная в системе может иметь разную версию. Это может привести к тому, что база данных в ОС, где установлена другая версия ICU, окажется бинарно несовместимой для индексов символьных типов данных.
Поскольку перестройка индексов может быть выполнена с использованием параллелизма, то и для gfix -icu
это тоже поддерживается.
2. Заключение
В этой части мы рассмотрели параллельные возможности инструментов Firebird 5. Если вы хотите узнать больше, как gbak реализует параллельное чтение данных или даже реализовать аналогичный механизм в своем приложении, прочтите подробную статью "Параллельное чтение данных в Firebird".
Мы рассказали ещё не про все новые возможности Firebird 5.0, следите за обновлениями!