На каком этапе жизненного цикла обработки запросов оцениваются постоянные функции времени выполнения? - PullRequest
1 голос
/ 06 апреля 2020

У меня есть таблица, которая содержит данные о событиях в моем приложении, и я хочу обрабатывать эти события по порядку, по одному за раз. Строки создаются (вставляются в таблицу) из триггера на другой таблице. Строки выбираются для обработки с использованием запроса в стиле UPDATE TOP 1 ... ORDER BY Id. Здравый смысл говорит, что строка должна быть создана до того, как она может быть выбрана, но во время нагрузочного тестирования очень редко дата и время, записанные для комплектации, ДО ДО даты, записанной для создания. относительно того, что происходит (основано главным образом на блоге из Коннор Каннингем связан с Использование функции в предложении where: сколько раз оценивается функция? ) - это выполнение create и запросы на выбор перекрываются, и sysutcdatetime () оценивается в start выполнения запроса, прежде чем ожидания приведут к завершению запросов sh в обратном порядке, в котором они были запущены. Примерно так (время движется вниз)

---------------------------------------------------
|Create Query            |Pick Query              |
===================================================
|                        |query start             |
---------------------------------------------------
|                        |evaluate sysutcdatetime |
---------------------------------------------------
|query start             |wait/block              |
---------------------------------------------------
|evaluate sysutcdatetime |wait/block              |
---------------------------------------------------
|insert rows using       |wait/block              |
|sysutcdatetime value    |                        |
|as Create timestamp     |                        |
---------------------------------------------------
|transaction commits     |wait/block              |
---------------------------------------------------
|                        |update top 1 using      |
|                        |sysutcdatetime value as |
|                        |Pick timestamp          |
---------------------------------------------------

Может кто-нибудь подтвердить, когда оцениваются постоянные функции времени выполнения? Или предоставьте альтернативное объяснение того, как дата и время, записанные для комплектации, могут быть ДО даты, записанной для создания?

Просто чтобы прояснить ситуацию, я хочу понять поведение, которое я вижу, а не способы изменить мою схему / код, чтобы устранить проблему go. Мое исправление на данный момент состоит в том, чтобы удалить ограничение проверки (PickedAt >= CreatedAt).


Для полноты, соответствующие части моей таблицы событий:

create table dbo.JobInstanceEvent (
    Id int identity not null constraint PK_JobInstanceEvent primary key,
    JobInstanceId int not null constraint FK_JobInstanceEvent_JobInstance foreign key references dbo.JobInstance (Id),
    JobInstanceStateCodeOld char(4) not null constraint FK_JobInstanceEvent_JobInstanceState1 foreign key references ref.JobInstanceState (Code),
    JobInstanceStateCodeNew char(4) not null constraint FK_JobInstanceEvent_JobInstanceState2 foreign key references ref.JobInstanceState (Code),
    JobInstanceEventStateCode char(4) not null constraint FK_JobInstance_JobInstanceEventState foreign key references ref.JobInstanceEventState (Code),
    CreatedAt datetime2 not null,
    PickedAt datetime2 null,
    FinishedAt datetime2 null,
    constraint CK_JobInstanceEvent_PickedAt check (PickedAt >= CreatedAt),
    constraint CK_JobInstanceEvent_FinishedAt check (FinishedAt >= PickedAt),
    constraint CK_JobInstanceEvent_PickedAt_FinishedAt check (PickedAt is null and FinishedAt is null or
                                                              PickedAt is not null) -- this covers the allowable combinations of PickedAt/FinishedAt
)

Оператор SQL, который создает новые строки:

insert dbo.JobInstanceEvent (JobInstanceId, JobInstanceStateCodeOld, JobInstanceStateCodeNew, JobInstanceEventStateCode, CreatedAt)
    select
        i.Id as JobInstanceId,
        d.JobInstanceStateCode as JobInstanceStateCodeOld,
        i.JobInstanceStateCode as JobInstanceStateCodeNew,
        'CRTD' as JobInstanceEventStateCode,
        sysutcdatetime() as CreatedAt
    from
        inserted i
            inner join deleted d on d.Id = i.Id
    where
        i.JobInstanceStateCode <> d.JobInstanceStateCode and -- the state has changed and
        i.JobInstanceStateCode in ('SUCC', 'FAIL')           -- the new state is either success or failure. 

Оператор SQL, который выбирает строку:

    ; with cte as (
        select top 1 
            jie.Id,
            jie.JobInstanceId,
            jie.JobInstanceStateCodeOld,
            jie.JobInstanceStateCodeNew,
            jie.JobInstanceEventStateCode,
            jie.PickedAt
        from
            dbo.JobInstanceEvent jie
        where
            jie.JobInstanceEventStateCode = 'CRTD'
        order by
            jie.Id
    )
    update cte set 
        JobInstanceEventStateCode = 'PICK', 
        PickedAt = sysutcdatetime()
    output 
        inserted.Id,
        inserted.JobInstanceId,
        inserted.JobInstanceStateCodeOld,
        inserted.JobInstanceStateCodeNew
    into 
        @PickedJobInstanceEvent

Я использую SQL Server 2016, но я не думаю, это спецификация версии c проблема.

1 Ответ

1 голос
/ 06 апреля 2020

объяснение того, как дата и время, записанные для комплектации, могут быть ДО даты, записанной для создания?

Вы можете смоделировать поведение диаграммы запроса создания / выбора, используя следующую (две ssms windows, для запросов на создание и получение)

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

create table dbo.atest
(
id int identity primary key clustered,
colA char(500) default('a'),
createddate datetime2(4) default(sysdatetime()),
pickeddate datetime2(4)
)
go

--rows already picked up
insert into dbo.atest(colA, createddate,pickeddate) 
values
('a', '20200405 12:00', '20200406 10:00'), 
('b', '20200405 12:00', '20200406 10:10'), 
('c', '20200405 12:00', '20200406 10:20'),
('d', '20200405 12:00', '20200406 10:30');

--create a new row..to be picked up
begin transaction  -- ...
update dbo.atest --..query start | wait block
set colA = colA

waitfor delay '00:00:40'
--during the waitfor delay, in another window(SSMS)
/*

--this will wait(blocking) for the delay and the insert and commit...
update a
set pickeddate = sysdatetime()
from
(
select top (1) *
from dbo.atest
where pickeddate is null
order by id 
) as a;

--insertion happened after the update was fired, picked<created
select *
from dbo.atest
where pickeddate < createddate;

*/   

--create new row
insert into dbo.atest(colA) values('e')

commit transaction
go

--drop table dbo.atest

Вы можете предотвратить выбор даты <созданный, включив условие в запрос выбора / загрузки: </p>

    from
        dbo.JobInstanceEvent jie
    where
        jie.JobInstanceEventStateCode = 'CRTD'
        and jie.CreatedAt < /*= ?*/ sysutcdatetime()
    order by
        jie.Id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...