Оптимизация нагрузки при использовании Quartz

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

Симптомы

Quartz создает большую нагрузку на базу данных.

Решение

  1. Для решения проблемы в первую очередь рекомендуется создать пользовательские планировщики, чтобы распределить нагрузку между ними.
  2. После чего выполнить перенос таблиц, работающих с Quartz, в отдельную таблицу в рамках одной базы данных.
  3. Если существуют ограничения в ресурсах основной базы данных, рекомендуется выполнить перенос таблиц, работающих с Quartz, в отдельную базу данных.

Это дает следующие преимущества:

  • Изоляцию блокировок: каждый планировщик работает со своими данными;
  • Повышение производительности: каждый планировщик сканирует только свои записи;
  • Безопасность: очистка одного планировщика не влияет на другие.

Перенос таблицы Quartz в рамках одной базы данных

Для перевода планировщика на другие таблицы в рамках одной базы данных выполните следующие шаги:

  1. Создайте новые таблицы для Quartz по аналогии с существующими (начинаются с qrtz_), но с собственным префиксом (например, custom_qrtz_: custom_qrtz_triggers и т. д.). Скрипты создания таблиц представлены в разделе Ресурсы.
  2. В блоке quartz для конкретного планировщика добавьте настройку для указания префикса таблицы:
<add key="quartz.jobStore.tablePrefix" value="custom_qrtz_" />

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

Для переноса таблицы выполните следующие шаги:

  1. В файле ConnectionStrings.config добавьте новую строку с названием, например, quartzDb:
<add name="quartzDb" connectionString="Server=..."/>
  1. В конфигурационном файле Web.config, который лежит в корневом каталоге приложения, в секции quartz, укажите новое название в параметре quartz.dataSource.SchedulerDb.connectionStringName:
<add key="quartz.dataSource.SchedulerDb.connectionStringName" value="quartzDb" />
Примечание. Значение параметра должно полностью совпадать с именем атрибута, заданным в шаге 1.
  1. Изменения нужно внести на всех экземплярах, чтобы сохранить кластерный режим.
  2. В базе данных, куда вы планируете перенаправить Quartz, должна быть идентичная основному приложению структура таблиц.
  3. Чтобы сохранить запланированные задания, необходимо заполнить таблицы данными.

Если потребуется перенос данных, рекомендуется следующий план действий:

  1. Остановите сайт и пул приложения BPMSoft.
  2. Создайте новую базу данных для Quartz и перенесите туда структуру и данные (можно просто скопировать основную базу данных сайта).
  3. Внесите изменения в файлы ConnectionStrings.config и Web.config сайта.
  4. Запустите сайт и пул приложения BPMSoft. Проверьте, что плановые задания выполняются корректно.

Если планировщик не запускается с первого раза и в логах нет ошибок, попробуйте перезайти под пользователем Supervisor:

  1. Войдите в систему под пользователем Supervisor.
  2. Нажмите кнопку «Выход».
  3. Повторно войдите в систему под пользователем Supervisor.

Ресурсы

Скрипт для Microsoft SQL Server

SET NOCOUNT ON;
SET XACT_ABORT ON;
GO
 
DECLARE
    @schema          sysname = N'dbo',
    @prefix          sysname = N'QRTZ_',
    @useVarbinaryMax bit     = 0;
 
DECLARE @blob nvarchar(20) = CASE WHEN @useVarbinaryMax = 1
                                  THEN N'VARBINARY(MAX)' ELSE N'IMAGE' END;
DECLARE @sql  nvarchar(max);
DECLARE @tbl  sysname;
DECLARE @full nvarchar(400);
DECLARE @msg  nvarchar(max);
 
IF @prefix IS NULL OR @prefix = N''
BEGIN
    THROW 50000, N'@prefix must not be empty', 1;
END;
 
IF NOT EXISTS (SELECT 1 FROM sys.schemas WHERE name = @schema)
BEGIN
    SET @msg = N'Schema "' + @schema + N'" does not exist in database "'
             + DB_NAME() + N'"';
    THROW 50000, @msg, 1;
END;
 
PRINT N'Quartz tables: database=' + DB_NAME()
    + N', schema=' + @schema + N', prefix=' + @prefix
    + N', blob type=' + @blob;
 
SET @tbl  = @prefix + N'JOB_DETAILS';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME]        NVARCHAR(100) NOT NULL,
        [JOB_NAME]          NVARCHAR(150) NOT NULL,
        [JOB_GROUP]         NVARCHAR(150) NOT NULL,
        [DESCRIPTION]       NVARCHAR(250) NULL,
        [JOB_CLASS_NAME]    NVARCHAR(250) NOT NULL,
        [IS_DURABLE]        BIT           NOT NULL,
        [IS_NONCONCURRENT]  BIT           NOT NULL,
        [IS_UPDATE_DATA]    BIT           NOT NULL,
        [REQUESTS_RECOVERY] BIT           NOT NULL,
        [JOB_DATA]          ' + @blob + N' NULL,
        CONSTRAINT ' + QUOTENAME(N'PK_' + @tbl) + N' PRIMARY KEY CLUSTERED
            ([SCHED_NAME], [JOB_NAME], [JOB_GROUP])
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
SET @tbl  = @prefix + N'TRIGGERS';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME]     NVARCHAR(100) NOT NULL,
        [TRIGGER_NAME]   NVARCHAR(150) NOT NULL,
        [TRIGGER_GROUP]  NVARCHAR(150) NOT NULL,
        [JOB_NAME]       NVARCHAR(150) NOT NULL,
        [JOB_GROUP]      NVARCHAR(150) NOT NULL,
        [DESCRIPTION]    NVARCHAR(250) NULL,
        [NEXT_FIRE_TIME] BIGINT        NULL,
        [PREV_FIRE_TIME] BIGINT        NULL,
        [PRIORITY]       INTEGER       NULL,
        [TRIGGER_STATE]  NVARCHAR(16)  NOT NULL,
        [TRIGGER_TYPE]   NVARCHAR(8)   NOT NULL,
        [START_TIME]     BIGINT        NOT NULL,
        [END_TIME]       BIGINT        NULL,
        [CALENDAR_NAME]  NVARCHAR(200) NULL,
        [MISFIRE_INSTR]  INTEGER       NULL,
        [JOB_DATA]       ' + @blob + N' NULL,
        CONSTRAINT ' + QUOTENAME(N'PK_' + @tbl) + N' PRIMARY KEY CLUSTERED
            ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]),
        CONSTRAINT ' + QUOTENAME(N'FK_' + @tbl + N'_' + @prefix + N'JOB_DETAILS')
            + N' FOREIGN KEY ([SCHED_NAME], [JOB_NAME], [JOB_GROUP])
            REFERENCES ' + QUOTENAME(@schema) + N'.'
            + QUOTENAME(@prefix + N'JOB_DETAILS')
            + N' ([SCHED_NAME], [JOB_NAME], [JOB_GROUP])
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
SET @tbl  = @prefix + N'SIMPLE_TRIGGERS';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME]      NVARCHAR(100) NOT NULL,
        [TRIGGER_NAME]    NVARCHAR(150) NOT NULL,
        [TRIGGER_GROUP]   NVARCHAR(150) NOT NULL,
        [REPEAT_COUNT]    INTEGER       NOT NULL,
        [REPEAT_INTERVAL] BIGINT        NOT NULL,
        [TIMES_TRIGGERED] INTEGER       NOT NULL,
        CONSTRAINT ' + QUOTENAME(N'PK_' + @tbl) + N' PRIMARY KEY CLUSTERED
            ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]),
        CONSTRAINT ' + QUOTENAME(N'FK_' + @tbl + N'_' + @prefix + N'TRIGGERS')
            + N' FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP])
            REFERENCES ' + QUOTENAME(@schema) + N'.'
            + QUOTENAME(@prefix + N'TRIGGERS')
            + N' ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP])
            ON DELETE CASCADE
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
SET @tbl  = @prefix + N'SIMPROP_TRIGGERS';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME]    NVARCHAR(100) NOT NULL,
        [TRIGGER_NAME]  NVARCHAR(150) NOT NULL,
        [TRIGGER_GROUP] NVARCHAR(150) NOT NULL,
        [STR_PROP_1]    NVARCHAR(512) NULL,
        [STR_PROP_2]    NVARCHAR(512) NULL,
        [STR_PROP_3]    NVARCHAR(512) NULL,
        [INT_PROP_1]    INT           NULL,
        [INT_PROP_2]    INT           NULL,
        [LONG_PROP_1]   BIGINT        NULL,
        [LONG_PROP_2]   BIGINT        NULL,
        [DEC_PROP_1]    NUMERIC(13,4) NULL,
        [DEC_PROP_2]    NUMERIC(13,4) NULL,
        [BOOL_PROP_1]   BIT           NULL,
        [BOOL_PROP_2]   BIT           NULL,
        [TIME_ZONE_ID]  NVARCHAR(80)  NULL,
        CONSTRAINT ' + QUOTENAME(N'PK_' + @tbl) + N' PRIMARY KEY CLUSTERED
            ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]),
        CONSTRAINT ' + QUOTENAME(N'FK_' + @tbl + N'_' + @prefix + N'TRIGGERS')
            + N' FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP])
            REFERENCES ' + QUOTENAME(@schema) + N'.'
            + QUOTENAME(@prefix + N'TRIGGERS')
            + N' ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP])
            ON DELETE CASCADE
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
SET @tbl  = @prefix + N'CRON_TRIGGERS';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME]      NVARCHAR(100) NOT NULL,
        [TRIGGER_NAME]    NVARCHAR(150) NOT NULL,
        [TRIGGER_GROUP]   NVARCHAR(150) NOT NULL,
        [CRON_EXPRESSION] NVARCHAR(120) NOT NULL,
        [TIME_ZONE_ID]    NVARCHAR(80)  NULL,
        CONSTRAINT ' + QUOTENAME(N'PK_' + @tbl) + N' PRIMARY KEY CLUSTERED
            ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP]),
        CONSTRAINT ' + QUOTENAME(N'FK_' + @tbl + N'_' + @prefix + N'TRIGGERS')
            + N' FOREIGN KEY ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP])
            REFERENCES ' + QUOTENAME(@schema) + N'.'
            + QUOTENAME(@prefix + N'TRIGGERS')
            + N' ([SCHED_NAME], [TRIGGER_NAME], [TRIGGER_GROUP])
            ON DELETE CASCADE
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
SET @tbl  = @prefix + N'BLOB_TRIGGERS';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME]    NVARCHAR(100) NOT NULL,
        [TRIGGER_NAME]  NVARCHAR(150) NOT NULL,
        [TRIGGER_GROUP] NVARCHAR(150) NOT NULL,
        [BLOB_DATA]     ' + @blob + N' NULL
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
SET @tbl  = @prefix + N'CALENDARS';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME]    NVARCHAR(100) NOT NULL,
        [CALENDAR_NAME] NVARCHAR(200) NOT NULL,
        [CALENDAR]      ' + @blob + N' NOT NULL,
        CONSTRAINT ' + QUOTENAME(N'PK_' + @tbl) + N' PRIMARY KEY CLUSTERED
            ([SCHED_NAME], [CALENDAR_NAME])
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
SET @tbl  = @prefix + N'PAUSED_TRIGGER_GRPS';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME]    NVARCHAR(100) NOT NULL,
        [TRIGGER_GROUP] NVARCHAR(150) NOT NULL,
        CONSTRAINT ' + QUOTENAME(N'PK_' + @tbl) + N' PRIMARY KEY CLUSTERED
            ([SCHED_NAME], [TRIGGER_GROUP])
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
SET @tbl  = @prefix + N'FIRED_TRIGGERS';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME]        NVARCHAR(100) NOT NULL,
        [ENTRY_ID]          NVARCHAR(95)  NOT NULL,
        [TRIGGER_NAME]      NVARCHAR(150) NOT NULL,
        [TRIGGER_GROUP]     NVARCHAR(150) NOT NULL,
        [INSTANCE_NAME]     NVARCHAR(200) NOT NULL,
        [FIRED_TIME]        BIGINT        NOT NULL,
        [SCHED_TIME]        BIGINT        NOT NULL,
        [PRIORITY]          INTEGER       NOT NULL,
        [STATE]             NVARCHAR(16)  NOT NULL,
        [JOB_NAME]          NVARCHAR(150) NULL,
        [JOB_GROUP]         NVARCHAR(150) NULL,
        [IS_NONCONCURRENT]  BIT           NULL,
        [REQUESTS_RECOVERY] BIT           NULL,
        CONSTRAINT ' + QUOTENAME(N'PK_' + @tbl) + N' PRIMARY KEY CLUSTERED
            ([SCHED_NAME], [ENTRY_ID])
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
SET @tbl  = @prefix + N'LOCKS';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME] NVARCHAR(100) NOT NULL,
        [LOCK_NAME]  NVARCHAR(40)  NOT NULL,
        CONSTRAINT ' + QUOTENAME(N'PK_' + @tbl) + N' PRIMARY KEY CLUSTERED
            ([SCHED_NAME], [LOCK_NAME])
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
SET @tbl  = @prefix + N'SCHEDULER_STATE';
SET @full = QUOTENAME(@schema) + N'.' + QUOTENAME(@tbl);
IF OBJECT_ID(@full, N'U') IS NULL
BEGIN
    SET @sql = N'CREATE TABLE ' + @full + N' (
        [SCHED_NAME]        NVARCHAR(100) NOT NULL,
        [INSTANCE_NAME]     NVARCHAR(200) NOT NULL,
        [LAST_CHECKIN_TIME] BIGINT        NOT NULL,
        [CHECKIN_INTERVAL]  BIGINT        NOT NULL,
        CONSTRAINT ' + QUOTENAME(N'PK_' + @tbl) + N' PRIMARY KEY CLUSTERED
            ([SCHED_NAME], [INSTANCE_NAME])
    )';
    EXEC sys.sp_executesql @sql;
    PRINT N'  created ' + @tbl;
END;
 
DECLARE @idx TABLE (idx_suffix nvarchar(100), tbl_suffix sysname, cols nvarchar(400));
 
INSERT INTO @idx (idx_suffix, tbl_suffix, cols) VALUES
    (N'T_C',                   N'TRIGGERS',       N'[SCHED_NAME],[CALENDAR_NAME]'),
    (N'T_G_J',                 N'TRIGGERS',       N'[TRIGGER_STATE],[SCHED_NAME],[JOB_GROUP],[JOB_NAME]'),
    (N'T_N_G_STATE',           N'TRIGGERS',       N'[SCHED_NAME],[TRIGGER_GROUP],[TRIGGER_STATE]'),
    (N'T_N_STATE',             N'TRIGGERS',       N'[SCHED_NAME],[TRIGGER_NAME],[TRIGGER_GROUP],[TRIGGER_STATE]'),
    (N'T_NEXT_FIRE_TIME',      N'TRIGGERS',       N'[SCHED_NAME],[NEXT_FIRE_TIME]'),
    (N'T_NFT_ST',              N'TRIGGERS',       N'[SCHED_NAME],[TRIGGER_STATE],[NEXT_FIRE_TIME]'),
    (N'T_NFT_ST_MISFIRE',      N'TRIGGERS',       N'[SCHED_NAME],[MISFIRE_INSTR],[NEXT_FIRE_TIME],[TRIGGER_STATE]'),
    (N'T_NFT_ST_MISFIRE_GRP',  N'TRIGGERS',       N'[SCHED_NAME],[MISFIRE_INSTR],[NEXT_FIRE_TIME],[TRIGGER_GROUP],[TRIGGER_STATE]'),
    (N'T_STATE',               N'TRIGGERS',       N'[SCHED_NAME],[TRIGGER_STATE]'),
    (N'FT_G_J',                N'FIRED_TRIGGERS', N'[SCHED_NAME],[JOB_GROUP],[JOB_NAME]'),
    (N'FT_G_T',                N'FIRED_TRIGGERS', N'[SCHED_NAME],[TRIGGER_GROUP],[TRIGGER_NAME]'),
    (N'FT_INST_JOB_REQ_RCVRY', N'FIRED_TRIGGERS', N'[SCHED_NAME],[INSTANCE_NAME],[REQUESTS_RECOVERY]');
 
DECLARE @iname sysname, @itbl sysname, @icols nvarchar(400);
 
DECLARE idx_cur CURSOR LOCAL FAST_FORWARD FOR
    SELECT N'IDX_' + @prefix + idx_suffix, @prefix + tbl_suffix, cols FROM @idx;
 
OPEN idx_cur;
FETCH NEXT FROM idx_cur INTO @iname, @itbl, @icols;
WHILE @@FETCH_STATUS = 0
BEGIN
    IF NOT EXISTS (SELECT 1 FROM sys.indexes
                   WHERE name = @iname
                     AND object_id = OBJECT_ID(QUOTENAME(@schema) + N'.'
                                             + QUOTENAME(@itbl)))
    BEGIN
        SET @sql = N'CREATE INDEX ' + QUOTENAME(@iname) + N' ON '
                 + QUOTENAME(@schema) + N'.' + QUOTENAME(@itbl)
                 + N' (' + @icols + N')';
        EXEC sys.sp_executesql @sql;
        PRINT N'  created index ' + @iname;
    END;
    FETCH NEXT FROM idx_cur INTO @iname, @itbl, @icols;
END;
CLOSE idx_cur;
DEALLOCATE idx_cur;
 
DECLARE @expected TABLE (tbl_suffix sysname, col_name sysname);
 
INSERT INTO @expected (tbl_suffix, col_name) VALUES
    (N'JOB_DETAILS', N'SCHED_NAME'),        (N'JOB_DETAILS', N'JOB_NAME'),
    (N'JOB_DETAILS', N'JOB_GROUP'),         (N'JOB_DETAILS', N'DESCRIPTION'),
    (N'JOB_DETAILS', N'JOB_CLASS_NAME'),    (N'JOB_DETAILS', N'IS_DURABLE'),
    (N'JOB_DETAILS', N'IS_NONCONCURRENT'),  (N'JOB_DETAILS', N'IS_UPDATE_DATA'),
    (N'JOB_DETAILS', N'REQUESTS_RECOVERY'), (N'JOB_DETAILS', N'JOB_DATA'),
 
    (N'TRIGGERS', N'SCHED_NAME'),     (N'TRIGGERS', N'TRIGGER_NAME'),
    (N'TRIGGERS', N'TRIGGER_GROUP'),  (N'TRIGGERS', N'JOB_NAME'),
    (N'TRIGGERS', N'JOB_GROUP'),      (N'TRIGGERS', N'DESCRIPTION'),
    (N'TRIGGERS', N'NEXT_FIRE_TIME'), (N'TRIGGERS', N'PREV_FIRE_TIME'),
    (N'TRIGGERS', N'PRIORITY'),       (N'TRIGGERS', N'TRIGGER_STATE'),
    (N'TRIGGERS', N'TRIGGER_TYPE'),   (N'TRIGGERS', N'START_TIME'),
    (N'TRIGGERS', N'END_TIME'),       (N'TRIGGERS', N'CALENDAR_NAME'),
    (N'TRIGGERS', N'MISFIRE_INSTR'),  (N'TRIGGERS', N'JOB_DATA'),
 
    (N'SIMPLE_TRIGGERS', N'SCHED_NAME'),      (N'SIMPLE_TRIGGERS', N'TRIGGER_NAME'),
    (N'SIMPLE_TRIGGERS', N'TRIGGER_GROUP'),   (N'SIMPLE_TRIGGERS', N'REPEAT_COUNT'),
    (N'SIMPLE_TRIGGERS', N'REPEAT_INTERVAL'), (N'SIMPLE_TRIGGERS', N'TIMES_TRIGGERED'),
 
    (N'SIMPROP_TRIGGERS', N'SCHED_NAME'),    (N'SIMPROP_TRIGGERS', N'TRIGGER_NAME'),
    (N'SIMPROP_TRIGGERS', N'TRIGGER_GROUP'), (N'SIMPROP_TRIGGERS', N'STR_PROP_1'),
    (N'SIMPROP_TRIGGERS', N'STR_PROP_2'),    (N'SIMPROP_TRIGGERS', N'STR_PROP_3'),
    (N'SIMPROP_TRIGGERS', N'INT_PROP_1'),    (N'SIMPROP_TRIGGERS', N'INT_PROP_2'),
    (N'SIMPROP_TRIGGERS', N'LONG_PROP_1'),   (N'SIMPROP_TRIGGERS', N'LONG_PROP_2'),
    (N'SIMPROP_TRIGGERS', N'DEC_PROP_1'),    (N'SIMPROP_TRIGGERS', N'DEC_PROP_2'),
    (N'SIMPROP_TRIGGERS', N'BOOL_PROP_1'),   (N'SIMPROP_TRIGGERS', N'BOOL_PROP_2'),
    (N'SIMPROP_TRIGGERS', N'TIME_ZONE_ID'),
 
    (N'CRON_TRIGGERS', N'SCHED_NAME'),      (N'CRON_TRIGGERS', N'TRIGGER_NAME'),
    (N'CRON_TRIGGERS', N'TRIGGER_GROUP'),   (N'CRON_TRIGGERS', N'CRON_EXPRESSION'),
    (N'CRON_TRIGGERS', N'TIME_ZONE_ID'),
 
    (N'BLOB_TRIGGERS', N'SCHED_NAME'),    (N'BLOB_TRIGGERS', N'TRIGGER_NAME'),
    (N'BLOB_TRIGGERS', N'TRIGGER_GROUP'), (N'BLOB_TRIGGERS', N'BLOB_DATA'),
 
    (N'CALENDARS', N'SCHED_NAME'), (N'CALENDARS', N'CALENDAR_NAME'),
    (N'CALENDARS', N'CALENDAR'),
 
    (N'PAUSED_TRIGGER_GRPS', N'SCHED_NAME'),
    (N'PAUSED_TRIGGER_GRPS', N'TRIGGER_GROUP'),
 
    (N'FIRED_TRIGGERS', N'SCHED_NAME'),    (N'FIRED_TRIGGERS', N'ENTRY_ID'),
    (N'FIRED_TRIGGERS', N'TRIGGER_NAME'),  (N'FIRED_TRIGGERS', N'TRIGGER_GROUP'),
    (N'FIRED_TRIGGERS', N'INSTANCE_NAME'), (N'FIRED_TRIGGERS', N'FIRED_TIME'),
    (N'FIRED_TRIGGERS', N'SCHED_TIME'),    (N'FIRED_TRIGGERS', N'PRIORITY'),
    (N'FIRED_TRIGGERS', N'STATE'),         (N'FIRED_TRIGGERS', N'JOB_NAME'),
    (N'FIRED_TRIGGERS', N'JOB_GROUP'),     (N'FIRED_TRIGGERS', N'IS_NONCONCURRENT'),
    (N'FIRED_TRIGGERS', N'REQUESTS_RECOVERY'),
 
    (N'LOCKS', N'SCHED_NAME'), (N'LOCKS', N'LOCK_NAME'),
 
    (N'SCHEDULER_STATE', N'SCHED_NAME'),
    (N'SCHEDULER_STATE', N'INSTANCE_NAME'),
    (N'SCHEDULER_STATE', N'LAST_CHECKIN_TIME'),
    (N'SCHEDULER_STATE', N'CHECKIN_INTERVAL');
 
DECLARE @problems nvarchar(max) = N'';
 
SELECT @problems = @problems + NCHAR(10) + N'  table ' + @schema + N'.'
                 + @prefix + t.tbl_suffix + N' is missing'
FROM (SELECT DISTINCT tbl_suffix FROM @expected) t
WHERE OBJECT_ID(QUOTENAME(@schema) + N'.'
              + QUOTENAME(@prefix + t.tbl_suffix), N'U') IS NULL;
 
SELECT @problems = @problems + NCHAR(10) + N'  column ' + @prefix + e.tbl_suffix
                 + N'.' + e.col_name + N' is missing'
FROM @expected e
WHERE OBJECT_ID(QUOTENAME(@schema) + N'.'
              + QUOTENAME(@prefix + e.tbl_suffix), N'U') IS NOT NULL
  AND NOT EXISTS (
        SELECT 1 FROM sys.columns c
        WHERE c.object_id = OBJECT_ID(QUOTENAME(@schema) + N'.'
                                    + QUOTENAME(@prefix + e.tbl_suffix))
          AND c.name = e.col_name);
 
IF @problems <> N''
BEGIN
    SET @msg = N'Quartz schema is incomplete:' + @problems + NCHAR(10)
             + N'A table with an older structure already existed and was left '
             + N'untouched. Compare it with the main application database and '
             + N'fix it manually, or drop it and re-run this script.';
    THROW 50000, @msg, 1;
END;
 
DECLARE @cnt int = (
    SELECT COUNT(*) FROM (SELECT DISTINCT tbl_suffix FROM @expected) t
    WHERE OBJECT_ID(QUOTENAME(@schema) + N'.'
                  + QUOTENAME(@prefix + t.tbl_suffix), N'U') IS NOT NULL);
 
PRINT N'OK: ' + CAST(@cnt AS nvarchar(10)) + N' Quartz tables with prefix "'
    + @prefix + N'" present in ' + DB_NAME() + N'.' + @schema;
GO

Скрипт для PostgreSQL

DO $bpm_quartz$
DECLARE
    v_schema text := 'public';
    v_prefix text := 'qrtz_';
 
    v_missing text := '';
    v_created int  := 0;
    v_exists  bool;
    r         record;
 
    c_expected constant text[][] := ARRAY[
        ['job_details',        'sched_name,job_name,job_group,description,job_class_name,is_durable,is_nonconcurrent,is_update_data,requests_recovery,job_data'],
        ['triggers',           'sched_name,trigger_name,trigger_group,job_name,job_group,description,next_fire_time,prev_fire_time,priority,trigger_state,trigger_type,start_time,end_time,calendar_name,misfire_instr,job_data'],
        ['simple_triggers',    'sched_name,trigger_name,trigger_group,repeat_count,repeat_interval,times_triggered'],
        ['simprop_triggers',   'sched_name,trigger_name,trigger_group,str_prop_1,str_prop_2,str_prop_3,int_prop_1,int_prop_2,long_prop_1,long_prop_2,dec_prop_1,dec_prop_2,bool_prop_1,bool_prop_2,time_zone_id'],
        ['cron_triggers',      'sched_name,trigger_name,trigger_group,cron_expression,time_zone_id'],
        ['blob_triggers',      'sched_name,trigger_name,trigger_group,blob_data'],
        ['calendars',          'sched_name,calendar_name,calendar'],
        ['paused_trigger_grps','sched_name,trigger_group'],
        ['fired_triggers',     'sched_name,entry_id,trigger_name,trigger_group,instance_name,fired_time,sched_time,priority,state,job_name,job_group,is_nonconcurrent,requests_recovery'],
        ['locks',              'sched_name,lock_name'],
        ['scheduler_state',    'sched_name,instance_name,last_checkin_time,checkin_interval']
    ];
BEGIN
    IF v_prefix IS NULL OR v_prefix = '' THEN
        RAISE EXCEPTION 'v_prefix must not be empty';
    END IF;
 
    PERFORM 1 FROM pg_namespace WHERE nspname = v_schema;
    IF NOT FOUND THEN
        RAISE EXCEPTION 'Schema "%" does not exist', v_schema;
    END IF;
 
    RAISE NOTICE 'Quartz tables: schema=%, prefix=%', v_schema, v_prefix;
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name        text    NOT NULL,
            job_name          text    NOT NULL,
            job_group         text    NOT NULL,
            description       text,
            job_class_name    text    NOT NULL,
            is_durable        boolean NOT NULL,
            is_nonconcurrent  boolean NOT NULL,
            is_update_data    boolean NOT NULL,
            requests_recovery boolean NOT NULL,
            job_data          bytea,
            CONSTRAINT %I PRIMARY KEY (sched_name, job_name, job_group)
        )$f$,
        v_schema, v_prefix || 'job_details',
        v_prefix || 'job_details_pkey');
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name     text     NOT NULL,
            trigger_name   text     NOT NULL,
            trigger_group  text     NOT NULL,
            job_name       text     NOT NULL,
            job_group      text     NOT NULL,
            description    text,
            next_fire_time bigint,
            prev_fire_time bigint,
            priority       integer,
            trigger_state  text     NOT NULL,
            trigger_type   text     NOT NULL,
            start_time     bigint   NOT NULL,
            end_time       bigint,
            calendar_name  text,
            misfire_instr  smallint,
            job_data       bytea,
            CONSTRAINT %I PRIMARY KEY (sched_name, trigger_name, trigger_group),
            CONSTRAINT %I FOREIGN KEY (job_group, sched_name, job_name)
                REFERENCES %I.%I (job_group, sched_name, job_name)
        )$f$,
        v_schema, v_prefix || 'triggers',
        v_prefix || 'triggers_pkey',
        v_prefix || 'triggers_sched_name_fkey',
        v_schema, v_prefix || 'job_details');
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name      text   NOT NULL,
            trigger_name    text   NOT NULL,
            trigger_group   text   NOT NULL,
            repeat_count    bigint NOT NULL,
            repeat_interval bigint NOT NULL,
            times_triggered bigint NOT NULL,
            CONSTRAINT %I PRIMARY KEY (sched_name, trigger_name, trigger_group),
            CONSTRAINT %I FOREIGN KEY (trigger_group, trigger_name, sched_name)
                REFERENCES %I.%I (trigger_group, trigger_name, sched_name)
                ON DELETE CASCADE
        )$f$,
        v_schema, v_prefix || 'simple_triggers',
        v_prefix || 'simple_triggers_pkey',
        v_prefix || 'simple_triggers_sched_name_fkey',
        v_schema, v_prefix || 'triggers');
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name    text NOT NULL,
            trigger_name  text NOT NULL,
            trigger_group text NOT NULL,
            str_prop_1    text,
            str_prop_2    text,
            str_prop_3    text,
            int_prop_1    integer,
            int_prop_2    integer,
            long_prop_1   bigint,
            long_prop_2   bigint,
            dec_prop_1    numeric,
            dec_prop_2    numeric,
            bool_prop_1   boolean,
            bool_prop_2   boolean,
            time_zone_id  text,
            CONSTRAINT %I PRIMARY KEY (sched_name, trigger_name, trigger_group),
            CONSTRAINT %I FOREIGN KEY (sched_name, trigger_name, trigger_group)
                REFERENCES %I.%I (sched_name, trigger_name, trigger_group)
                ON DELETE CASCADE
        )$f$,
        v_schema, v_prefix || 'simprop_triggers',
        v_prefix || 'simprop_triggers_pkey',
        v_prefix || 'simprop_triggers_sched_name_fkey',
        v_schema, v_prefix || 'triggers');
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name      text NOT NULL,
            trigger_name    text NOT NULL,
            trigger_group   text NOT NULL,
            cron_expression text NOT NULL,
            time_zone_id    text,
            CONSTRAINT %I PRIMARY KEY (sched_name, trigger_name, trigger_group),
            CONSTRAINT %I FOREIGN KEY (trigger_group, trigger_name, sched_name)
                REFERENCES %I.%I (trigger_group, trigger_name, sched_name)
                ON DELETE CASCADE
        )$f$,
        v_schema, v_prefix || 'cron_triggers',
        v_prefix || 'cron_triggers_pkey',
        v_prefix || 'cron_triggers_sched_name_fkey',
        v_schema, v_prefix || 'triggers');
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name    text NOT NULL,
            trigger_name  text NOT NULL,
            trigger_group text NOT NULL,
            blob_data     bytea,
            CONSTRAINT %I PRIMARY KEY (sched_name, trigger_name, trigger_group),
            CONSTRAINT %I FOREIGN KEY (sched_name, trigger_name, trigger_group)
                REFERENCES %I.%I (sched_name, trigger_name, trigger_group)
                ON DELETE CASCADE
        )$f$,
        v_schema, v_prefix || 'blob_triggers',
        v_prefix || 'blob_triggers_pkey',
        v_prefix || 'blob_triggers_sched_name_fkey',
        v_schema, v_prefix || 'triggers');
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name    text  NOT NULL,
            calendar_name text  NOT NULL,
            calendar      bytea NOT NULL,
            CONSTRAINT %I PRIMARY KEY (sched_name, calendar_name)
        )$f$,
        v_schema, v_prefix || 'calendars',
        v_prefix || 'calendars_pkey');
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name    text NOT NULL,
            trigger_group text NOT NULL,
            CONSTRAINT %I PRIMARY KEY (sched_name, trigger_group)
        )$f$,
        v_schema, v_prefix || 'paused_trigger_grps',
        v_prefix || 'paused_trigger_grps_pkey');
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name        text    NOT NULL,
            entry_id          text    NOT NULL,
            trigger_name      text    NOT NULL,
            trigger_group     text    NOT NULL,
            instance_name     text    NOT NULL,
            fired_time        bigint  NOT NULL,
            sched_time        bigint  NOT NULL,
            priority          integer NOT NULL,
            state             text    NOT NULL,
            job_name          text,
            job_group         text,
            is_nonconcurrent  boolean NOT NULL,
            requests_recovery boolean,
            CONSTRAINT %I PRIMARY KEY (sched_name, entry_id)
        )$f$,
        v_schema, v_prefix || 'fired_triggers',
        v_prefix || 'fired_triggers_pkey');
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name text NOT NULL,
            lock_name  text NOT NULL,
            CONSTRAINT %I PRIMARY KEY (sched_name, lock_name)
        )$f$,
        v_schema, v_prefix || 'locks',
        v_prefix || 'locks_pkey');
 
    EXECUTE format($f$
        CREATE TABLE IF NOT EXISTS %I.%I (
            sched_name        text   NOT NULL,
            instance_name     text   NOT NULL,
            last_checkin_time bigint NOT NULL,
            checkin_interval  bigint NOT NULL,
            CONSTRAINT %I PRIMARY KEY (sched_name, instance_name)
        )$f$,
        v_schema, v_prefix || 'scheduler_state',
        v_prefix || 'scheduler_state_pkey');
 
    FOR r IN
        SELECT * FROM (VALUES
            ('ft_job_group',        'fired_triggers', 'job_group'),
            ('ft_job_name',         'fired_triggers', 'job_name'),
            ('ft_job_req_recovery', 'fired_triggers', 'requests_recovery'),
            ('ft_trig_group',       'fired_triggers', 'trigger_group'),
            ('ft_trig_inst_name',   'fired_triggers', 'instance_name'),
            ('ft_trig_name',        'fired_triggers', 'trigger_name'),
            ('ft_trig_nm_gp',       'fired_triggers', 'sched_name, trigger_name, trigger_group'),
            ('j_req_recovery',      'job_details',    'requests_recovery'),
            ('t_next_fire_time',    'triggers',       'next_fire_time'),
            ('t_nft_st',            'triggers',       'next_fire_time, trigger_state'),
            ('t_state',             'triggers',       'trigger_state')
        ) AS x(idx_suffix, tbl_suffix, cols)
    LOOP
        EXECUTE format('CREATE INDEX IF NOT EXISTS %I ON %I.%I USING btree (%s)',
            'idx_' || v_prefix || r.idx_suffix,
            v_schema, v_prefix || r.tbl_suffix,
            r.cols);
    END LOOP;
 
    FOR i IN 1 .. array_length(c_expected, 1) LOOP
        SELECT EXISTS (
            SELECT 1 FROM information_schema.tables
            WHERE table_schema = v_schema
              AND table_name   = v_prefix || c_expected[i][1]
        ) INTO v_exists;
 
        IF NOT v_exists THEN
            v_missing := v_missing || format(E'\n  table %s.%s is missing',
                                             v_schema, v_prefix || c_expected[i][1]);
            CONTINUE;
        END IF;
 
        FOR r IN SELECT unnest(string_to_array(c_expected[i][2], ',')) AS col LOOP
            SELECT EXISTS (
                SELECT 1 FROM information_schema.columns
                WHERE table_schema = v_schema
                  AND table_name   = v_prefix || c_expected[i][1]
                  AND column_name  = r.col
            ) INTO v_exists;
 
            IF NOT v_exists THEN
                v_missing := v_missing || format(E'\n  column %s.%s is missing',
                                                 v_prefix || c_expected[i][1], r.col);
            END IF;
        END LOOP;
    END LOOP;
 
    IF v_missing <> '' THEN
        RAISE EXCEPTION 'Quartz schema is incomplete:%', v_missing
            USING HINT = 'A table with an older structure already existed and was '
                         'left untouched by CREATE TABLE IF NOT EXISTS. '
                         'Compare it with the main application database and fix it '
                         'manually, or drop it and re-run this script.';
    END IF;
 
    SELECT count(*) INTO v_created
    FROM information_schema.tables
    WHERE table_schema = v_schema
      AND table_name LIKE v_prefix || '%';
 
    RAISE NOTICE 'OK: % tables with prefix "%" present in schema "%"',
                 v_created, v_prefix, v_schema;
END
$bpm_quartz$;

Рекомендуем изучить

Диагностика и решение проблем планировщика Quartz
Создание пользовательского планировщика Quartz

Материал был полезен для вас?
Запросить демонстрацию
Купить приложение
Заявка на индивидуальный тренинг
Заявка на обучение в формате тренинга
Заявка на консультацию по обучению
Готовы сделать выбор CRM? (детальная)
Оставьте заявку, и наши эксперты бесплатно проконсультируют вас, подберут подходящую конфигурацию и рассчитают стоимость проекта.
Предпочитаемый способ связи
Вебинар: 10 ноября в 11:00
Разберём, как повысить эффективность управления ИТ-инфраструктурой с помощью ITSM и Service Desk. Обсудим, как сократить операционные затраты и ускорить бизнес-процессы в 2 раза, на реальном опыте ПАО «Трубная металлургическая компания» (ТМК) и Группы Rubytech.
Готовы сделать выбор CRM?
Оставьте заявку, и наши эксперты бесплатно проконсультируют вас, подберут подходящую конфигурацию и рассчитают стоимость проекта.
Предпочитаемый способ связи
Готовы сделать выбор CRM? (детальная)
Оставьте заявку, и наши эксперты бесплатно проконсультируют вас, подберут подходящую конфигурацию и рассчитают стоимость проекта.
Предпочитаемый способ связи
Готовы сделать выбор CRM?
Оставьте заявку, и наши эксперты бесплатно проконсультируют вас, подберут подходящую конфигурацию и рассчитают стоимость проекта.
Предпочитаемый способ связи
Регистрация на мероприятие
Типовое внедрение
Внедрите BPMSoft CRM в свою компанию всего за 8 рабочих дней по фиксированной цене! Заполните заявку для уточнения условий.
Предпочитаемый способ связи
Оставить заявку
Оставьте свои контакты, и наш менеджер свяжется с Вами в ближайшее время.
Предпочитаемый способ связи
Демонстрационная версия BPMSoft
Заполните заявку для получения бесплатного доступа к демонстрационному стенду на 14 дней.
Заказать презентацию
Наш менеджер свяжется с Вами в ближайшее время.
Предпочитаемый способ связи
Рассчитать стоимость
Предпочитаемый способ связи
Лучшие CRM-системы в России: выводы Фонда «Сколково»
Задать вопрос
Предпочитаемый способ связи
Есть вопросы?
Не нашли для себя подходящую вакансию, или остались вопросы?
*
Есть вопросы?
Не нашли для себя подходящую вакансию, или остались вопросы?
*
Присоединяйтесь к партнерской сети BPMSoft
Оставьте свои контакты, и наш менеджер свяжется с Вами в ближайшее время
Тип партнерства*
Управление полным жизненным циклом клиента: от генерации лидов и продаж до внедрения, поддержки и продления подписки.
Разработка собственного Приложения – производного программного обеспечения, созданного на платформе BPMSoft (Базовое ПО).
Заявка на онлайн-консультации по BPMSoft
Оставьте свои контакты, и наш менеджер свяжется с Вами в ближайшее время
Стать образовательным партнёром
Оставьте свои контакты, и наш менеджер свяжется с Вами в ближайшее время.
Заявка на консультацию
Оставьте свои контакты, и наш менеджер свяжется с Вами в ближайшее время.
Подписка
Спасибо!
Ваша заявка принята.
Спасибо!
Ваша заявка принята.
Наш сотрудник свяжется с вами в течение 1-2 рабочих дней.
Внимание!
Обнаружена ошибка.
Внимание!
Обнаружена ошибка.
Вы подписаны на новостную рассылку от BPMSoft.
Вы подписаны на новостную рассылку от BPMSoft.
MAX Подписаться
Уважаемые клиенты! Предупреждаем о случаях недобросовестной конкуренции и мошенничестве в сети Интернет.
Подробнее