Оптимизировать таблицу базы данных SQL для многократных записей, одно чтение - PullRequest
0 голосов
/ 04 декабря 2018

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

Я буду охватывать 40-50 потоков, на завершение которых может потребоваться несколько минут или даже часов, и они обновят свой статус до данных.

Из веб-приложения я создам механизм опроса, который будет считывать состояние процессов, используя одно чтение каждые 0,5 секунды.

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

Это таблица, которую я использую

CREATE TABLE [cmn].[ProcessProgress]
(
    [id] [bigint] NOT NULL,
    [status] [smallint] NOT NULL,
    [step] [int] NOT NULL,
    [max_step] [int] NOT NULL,

    CONSTRAINT [PK_ProcessProgress] PRIMARY KEY CLUSTERED
    (
        [id] ASC
    ) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY  = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) 
GO

И выберите с помощью(NOLOCK) Полагаю, мне нужно использовать

SELECT * FROM [cmn].[ProcessProgress] (NOLOCK)

Нужно ли использовать транзакцию со специальным ISOLATION LEVEL или достаточно (nolock)?Или (nolock) заставит думать хуже?

Можете ли вы предложить наиболее оптимальное решение этой проблемы?

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

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

if object_id('ProcessProgress') is not null
    drop table ProcessProgress
    Go

CREATE TABLE [ProcessProgress]
(
    [id] [bigint] NOT NULL IDENTITY(1,1), --added identity to shorten sample dev
    [status] [smallint] NOT NULL, --1 -ready,2-inprogress, 3-complete
    [step] [int] NOT NULL,
    [max_step] [int] NOT NULL,

    CONSTRAINT [PK_ProcessProgress] PRIMARY KEY CLUSTERED
    (
        [id] ASC
    ) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY  = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) 
GO
SET NOCOUNT ON
INSERT INTO [ProcessProgress]
    (status, step, max_step)
VALUES
    (1, 1, 1)
GO 1000

Go
IF OBJECT_ID('StartWork') is not null drop proc StartWork
GO
CREATE PROC StartWork
AS
BEGIN
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED

    BEGIN TRAN
        ;WITH TODO
        AS (
            SELECT TOP 1 Id, [status] from ProcessProgress WITH (ROWLOCK, READPAST) WHERE [status] = 1 --ready
        )
        UPDATE TODO 
            SET [status] = 2 --InProgress
        OUTPUT inserted.id 

    COMMIT
END
GO

IF OBJECT_ID('FinishWork') is not null drop proc FinishWork
GO
CREATE PROC FinishWork
    @id int
AS
BEGIN
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    BEGIN TRAN

    Update  ProcessProgress
        SET [Status] = 3 --finished
    WHERE
        id = @id

    COMMIT
END
GO


/*tester*/
declare @idout table (id int)
insert into @idout exec StartWork

declare @idin int = (Select top 1 id from @idout)
exec FinishWork @idin
0 голосов
/ 04 декабря 2018

Просто установите параметр READ_COMMITTED_SNAPSHOT в вашей базе данных, и читатели и писатели никогда не будут конфликтовать.Вместо этого они будут использовать Row Versioning :

alter database current set read_committed_snapshot on

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

...