SQL Server: `append_events` does not need the `@inserted` table variable
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 20/100
Hướng nghiên cứu
The change is in src/SqlServer/src/Eventuous.SqlServer/Scripts/2_AppendEvents.sql: remove the @inserted table variable and get the highest GlobalPosition from SCOPE_IDENTITY(). Check that the nested check_stream procedure runs in a separate scope so it does not change the value. Done means the append and concurrency tests pass and the table variable is gone. Pull request #621 is already open against this issue, so check it before starting.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
append_events writes the new GlobalPosition values into a table variable, only to read their maximum at the end:
DECLARE @inserted TABLE (GlobalPosition BIGINT);
INSERT INTO __schema__.Messages (...)
OUTPUT inserted.GlobalPosition
INTO @inserted (GlobalPosition)
SELECT ... FROM @messages;
...
SELECT @position = (SELECT MAX(GlobalPosition) FROM @inserted);
A statement that writes to a table variable always gets a serial plan, and the OUTPUT ... INTO adds a write to tempdb for each appended event. The procedure can get the same value without the table variable.
How I found it
We capture the actual execution plans from our integration tests and analyze them with Performance Studio. It reports these statements in append_events:
| Severity | Statement | Message |
|---|---|---|
| Critical | INSERT INTO eventuous.Messages (...) OUTPUT ... INTO @inserted |
This query modifies a table variable, which forces the entire plan to run single-threaded. |
| Warning | INSERT INTO eventuous.Messages (...) |
Table variable detected. Table variables lack column-level statistics... |
| Warning | SELECT @position = (SELECT MAX(GlobalPosition) FROM @inserted) |
Table variable detected. |
| Warning | SELECT @count_messages = COUNT(1) FROM @messages |
Table variable detected. |
To be clear about the impact: an append usually has few events, so a serial plan costs almost nothing. The real gain is a simpler procedure with one less tempdb write per event. The warnings on @messages are not actionable, because @messages is the table-valued parameter and cannot be a #temp table.
Environment: Eventuous 0.17.0, SQL Server 2022. src/SqlServer/src/Eventuous.SqlServer/Scripts/2_AppendEvents.sql on dev has the same code.
Suggested change
GlobalPosition is an IDENTITY column, and the procedure inserts all events in one statement. SCOPE_IDENTITY() returns the last identity value that this statement generated, which is the highest GlobalPosition of the batch. The insert into Streams in check_stream runs in a different scope (a nested procedure), so it does not change the value.
INSERT INTO __schema__.Messages (
MessageId, MessageType, StreamId, StreamPosition, JsonData, JsonMetadata, Created
)
SELECT
message_id,
message_type,
@stream_id,
@current_version + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS INT),
json_data,
json_metadata,
ISNULL(@created, SYSUTCDATETIME())
FROM @messages;
SET @position = SCOPE_IDENTITY();
Then remove the DECLARE @inserted TABLE and the final SELECT @position = (... FROM @inserted). If @messages is empty, SCOPE_IDENTITY() returns NULL, which is the same result that MAX over an empty @inserted gives now.
The existing append and concurrency tests should cover this change. I can open a PR if you agree.
- Ngôn ngữ chính
- C#
- Star
- 512
- Fork
- 99
- Merge trung bình
- 6 ngày 17 giờ
- Pull request đã merge (30 ngày)
- 2
Chuẩn bị môi trường
- Có Dockerfile hoặc tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của Eventuous/eventuous
-
MongoDB integration tests fail on newer GitHub Actions runner kernelsCó thể đã có người làm @nmummau đã nhận 15 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
-
`dotnet format style --verify-no-changes` fails with naming violations and unnecessary importsCó thể đã có người làm @nmummau đã nhận 15 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 80/100
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
-
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 35/100
-
SQL Server: stream reads do one key lookup per event, and `IDX_EventsStream` duplicates `UQ_StreamIdAndStreamPosition`Có thể đã có người làm @nmummau đã nhận 21 ngày trước. Đang mở
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 18/100
Tất cả issue của Eventuous/eventuous
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
KnifeLemon/Filee#1118 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 72/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
Facepunch/sbox-public#12284 ·
Maintainer thường phản hồi trong vòng 6 ngày
-
bug untriaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 67/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
CarlosAdrianM/Nesto#610 ·