Chỉ chèn các khóa chết


7

Chúng tôi có một ứng dụng chèn dữ liệu vào một bảng. Thật không may, chúng tôi đang nhận được bế tắc và bế tắc chỉ đến từ chèn. Chúng ta đang thấy các phần chèn có các khóa chính theo một thứ tự khác trên một chỉ mục không bao gồm gây ra vấn đề.

Tại sao các chèn chèn hành xử theo cách này và chúng ta nên làm gì để cố gắng giảm bớt bế tắc? Bất kỳ trợ giúp hoặc cái nhìn sâu sắc được đánh giá cao.

Trong ví dụ dưới đây, chỉ có hai phần chèn liên quan, nhưng chúng tôi đã có tới 4 phần chèn khác nhau liên quan đến bế tắc.

Dưới đây là biểu đồ khóa chết:

    <deadlock>
    <victim-list>
        <victimProcess id="process3ab355868" />
    </victim-list>
    <process-list>
        <process id="process3ab355868" taskpriority="0" logused="1184" waitresource="KEY: 5:72057594043629568 (6234ed5bf036)" waittime="7493" ownerId="92332106" transactionname="implicit_transaction" lasttranstarted="2014-10-13T12:37:43.060" XDES="0x123699668" lockMode="X" schedulerid="3" kpid="3540" status="suspended" spid="89" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2014-10-13T12:37:44.333" lastbatchcompleted="2014-10-13T12:37:44.333" lastattention="1900-01-01T00:00:00.333" clientapp="Microsoft JDBC Driver for SQL Server" hostname="" hostpid="0" loginname="" isolationlevel="read committed (2)" xactid="92332106" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
            <executionStack>
                <frame procname="adhoc" line="1" stmtstart="278" stmtend="818" sqlhandle="0x0200000053a65d302154b91e9fee55234669030a42479c050000000000000000000000000000000000000000">
                    INSERT INTO table (col1, col2, col3, col4, col5, col6, col7, col8, col9) VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)
                </frame>
                <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
                    unknown
                </frame>
            </executionStack>
            <inputbuf>
                (@P0 datetime2,@P1 nvarchar(4000),@P2 nvarchar(4000),@P3 datetime2,@P4 nvarchar(4000),@P5 nvarchar(4000),@P6 decimal(38,1),@P7 int,@P8 int)INSERT INTO table (col1, col2, col3, col4, col5, col6, col7, col8, col9) VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)                                                                         select SCOPE_IDENTITY() AS GENERATED_KEYS
            </inputbuf>
        </process>
        <process id="process14b38c928" taskpriority="0" logused="2564" waitresource="KEY: 5:72057594043629568 (275232b7b238)" waittime="7491" ownerId="92325909" transactionname="implicit_transaction" lasttranstarted="2014-10-13T12:37:39.567" XDES="0x16b38b988" lockMode="X" schedulerid="3" kpid="3668" status="suspended" spid="65" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2014-10-13T12:37:44.337" lastbatchcompleted="2014-10-13T12:37:44.337" lastattention="1900-01-01T00:00:00.337" clientapp="Microsoft JDBC Driver for SQL Server" hostname="" hostpid="0" loginname="" isolationlevel="read committed (2)" xactid="92325909" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
            <executionStack>
                <frame procname="adhoc" line="1" stmtstart="278" stmtend="818" sqlhandle="0x0200000053a65d302154b91e9fee55234669030a42479c050000000000000000000000000000000000000000">
                    INSERT INTO table (col1, col2, col3, col4, col5, col6, col7, col8, col9) VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)
                </frame>
                <frame procname="unknown" line="1" sqlhandle="0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000">
                    unknown
                </frame>
            </executionStack>
            <inputbuf>
                (@P0 datetime2,@P1 nvarchar(4000),@P2 nvarchar(4000),@P3 datetime2,@P4 nvarchar(4000),@P5 nvarchar(4000),@P6 decimal(38,1),@P7 int,@P8 int)INSERT INTO table (col1, col2, col3, col4, col5, col6, col7, col8, col9) VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)                                                                         select SCOPE_IDENTITY() AS GENERATED_KEYS
            </inputbuf>
        </process>
    </process-list>
    <resource-list>
        <keylock hobtid="72057594043629568" dbid="5" objectname="table1" indexname="unique_index" id="lock17bc3a480" mode="X" associatedObjectId="72057594043629568">
            <owner-list>
                <owner id="process14b38c928" mode="X" />
            </owner-list>
            <waiter-list>
                <waiter id="process3ab355868" mode="X" requestType="wait" />
            </waiter-list>
        </keylock>
        <keylock hobtid="72057594043629568" dbid="5" objectname="table1" indexname="unique_index" id="lock10735ce00" mode="X" associatedObjectId="72057594043629568">
            <owner-list>
                <owner id="process3ab355868" mode="X" />
            </owner-list>
            <waiter-list>
                <waiter id="process14b38c928" mode="X" requestType="wait" />
            </waiter-list>
        </keylock>
    </resource-list>
</deadlock>

Đây là bảng DDL:

CREATE TABLE [table1](
    [col0] [int] IDENTITY(1,1) NOT NULL,
    [col1] [int] NOT NULL,
    [col2] [int] NOT NULL,
    [col3] [decimal](15, 4) NULL,
    [col4] [datetime2](7) NOT NULL,
    [col5] [varchar](8) NOT NULL,
    [col6] [varchar](30) NOT NULL,
    [col7] [datetime2](7) NOT NULL,
    [col8] [varchar](8) NOT NULL,
    [col9] [varchar](30) NOT NULL,
 CONSTRAINT [PK] PRIMARY KEY CLUSTERED 
(
    [col0] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
 CONSTRAINT [unique_index] UNIQUE NONCLUSTERED 
(
    [col2] ASC,
    [col1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

ALTER TABLE table1 ADD  DEFAULT (sysdatetime()) FOR [col4]
GO

ALTER TABLE table1 ADD  DEFAULT (sysdatetime()) FOR [col7]
GO

Là những chèn một phần của một giao dịch lớn hơn?
Aaron Bertrand

Các phần chèn là một phần của các giao dịch mà mỗi phần thực hiện khoảng 6 hoặc 7 trong số các phần chèn này.
GoodwinSQL

Bạn có thể hiển thị tất cả các mã? Khó khắc phục sự cố chỉ với thông tin bế tắc, bởi vì nó không nắm bắt được tất cả các chi tiết.
Aaron Bertrand

Thật không may, hiện tại tôi không có quyền truy cập vào tất cả các mã.
GoodwinQuery

Vì vậy, nếu cách xây dựng mã là vấn đề, bạn sẽ sửa nó như thế nào?
Aaron Bertrand

Câu trả lời:


7

Tôi đang trả lời câu hỏi của riêng mình ở đây vì cuối cùng chúng tôi đã tìm ra vấn đề.

Phiên bản ngắn: Chúng tôi đã thêm một cột thứ ba vào chỉ mục không bao gồm. Bế tắc biến mất.

Phiên bản dài:

Đầu tiên, hãy xem bài đăng trên blog năng động của James Rowland-Jones về va chạm băm khóa (Lời giải thích của tôi sẽ không giống với chất lượng của anh ấy).

Từ bài viết trên blog:

Khi SQL Server cần khóa một hàng, nó tạo ra một giá trị băm dựa trên các giá trị chính của bảng. Đó là giá trị băm này được sử dụng bởi trình quản lý khóa và có nghĩa là nó có một giá trị duy nhất để xem xét khi kiểm tra xem một hàng đã bị khóa hay chưa.

Xung đột băm khóa xảy ra khi các giá trị băm trùng lặp được tạo ra.

Sau khi thực hiện một số phân tích sâu hơn về nhiều biểu đồ khóa chết, chúng tôi nhận thấy rằng rất nhiều giá trị băm khóa WAITRESOURCE (các giá trị giữa dấu ngoặc đơn) là như nhau. Tôi bắt đầu lập một danh sách ngắn để theo dõi:

waitresource="KEY: 5:72057594043629568 (a27543d90a1a)
waitresource="KEY: 5:72057594043629568 (a27543d90a1a)
waitresource="KEY: 5:72057594043629568 (8328314847df)
waitresource="KEY: 5:72057594043629568 (bb0d06c12baa)
waitresource="KEY: 5:72057594043629568 (a27543d90a1a)
waitresource="KEY: 5:72057594043629568 (bb0d06c12baa)
waitresource="KEY: 5:72057594043629568 (8328314847df)
waitresource="KEY: 5:72057594043629568 (bb0d06c12baa)
waitresource="KEY: 5:72057594043629568 (a27543d90a1a)
waitresource="KEY: 5:72057594043629568 (5b39284eef16)
waitresource="KEY: 5:72057594043629568 (a27543d90a1a)
waitresource="KEY: 5:72057594043629568 (8328314847df)
waitresource="KEY: 5:72057594043629568 (5b39284eef16)

Chắc chắn, chúng tôi đã nhận được rất nhiều giá trị băm trùng lặp từ các biểu đồ khóa chết khác nhau. Tôi quyết định xem xét dữ liệu trong hai cột (col2 & col1) của chỉ số unique_index (nơi xảy ra các bế tắc). Tất cả các bảng DDL là ở trên trong câu hỏi.

Cột col2 luôn có giá trị 1-6 cho một giá trị trong cột col1. Vì vậy, điều này bắt đầu có ý nghĩa. Có rất nhiều dữ liệu hạn chế có sẵn cho SQL để tạo các giá trị băm từ đó - điều này giải thích tại sao chúng tôi nhận được các giá trị băm trùng lặp.

Một trong những cách khắc phục mà JRJ đã đề cập trong blog là thêm một cột bổ sung vào chỉ mục. Điều này thêm một số đa dạng cho dữ liệu và cung cấp thêm tùy chọn cho thuật toán băm. May mắn thay, chúng tôi đã có thể thêm một cột created_timestamp vào chỉ mục và duy trì tính duy nhất giống như chúng tôi có với hai cột. BÙM! Sau khi thêm cột thứ ba vào chỉ mục, các khóa chết biến mất.

Sidenote: Một trong những bình luận trên blog đề nghị vô hiệu hóa khóa hàng trên chỉ mục. Chúng tôi đã thử điều này đầu tiên. Nó đã thoát khỏi những bế tắc, nhưng dẫn đến khóa nhiều hơn và cắt giảm thông lượng tổng thể xuống khoảng 40-50% vì vậy chúng tôi không thích tùy chọn này cho hệ thống của mình. Tuy nhiên, trên cơ sở dữ liệu với khối lượng công việc nhẹ hơn, điều này có thể hoạt động tốt.

Hy vọng tất cả điều này có ý nghĩa.


0

Tôi không chắc liệu điều này có thực sự có thể trả lời hay không nhưng tôi không thể đăng bài này dưới dạng bình luận.

Nếu bạn thấy mã ứng dụng của mình giống như

@P1 nvarchar(4000)
,@P2 nvarchar(4000),
@P3 datetime2,
@P4 nvarchar(4000),
@P5 nvarchar(4000),
@P6 decimal(38,1),
@P7 int,
@P8 int)
INSERT INTO OBC.MBL_CPU_POS_MSR_ATB (
CRT_S, 
CRT_PGM_C, 
CRT_UID, 
LST_UPD_S, 
LST_UPD_PGM_C,
 LST_UPD_UID, 
MSR_ATB_VAL, 
MBL_CPU_POS_I, 
POS_MSR_TYP_I) 
VALUES (@P0, @P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)                                                                         select SCOPE_IDENTITY() AS GENERATED_KEYS

Nếu bạn thấy bạn đã khai báo @p4,@p5...@P6như nvarchar()nhưng nếu bạn thấy định nghĩa bảng

CREATE TABLE [OBC].[MBL_CPU_POS_MSR_ATB](
    [MBL_CPU_POS_MSR_ATB_I] [int] IDENTITY(1,1) NOT NULL,
    [POS_MSR_TYP_I] [int] NOT NULL,
    [MBL_CPU_POS_I] [int] NOT NULL,
    [MSR_ATB_VAL] [decimal](15, 4) NULL,
    [CRT_S] [datetime2](7) NOT NULL,
    [CRT_UID] [varchar](8) NOT NULL,
    [CRT_PGM_C] [varchar](30) NOT NULL,
    [LST_UPD_S] [datetime2](7) NOT NULL,
    [LST_UPD_UID] [varchar](8) NOT NULL,
    [LST_UPD_PGM_C] [varchar](30) NOT NULL,

Cột trong đó họ đang chèn giá trị được khai báo là varcharvà giá trị bạn đang truyền là nvarchar. Không có cột trong bảng của bạn có nvarcharkiểu dữ liệu. Nếu đây là sự chuyển đổi ngầm định thực sự sẽ xảy ra và quét chỉ mục sẽ xảy ra thay vì tìm cách giữ khóa (đặc biệt khi bạn đã cập nhật) trong thời gian dài hơn. Tôi đoán điều này có thể là nguyên nhân của bế tắc.

Ngoài ra còn có trancount = 2 có nghĩa là có giao dịch không được cam kết và tất nhiên bit nếu điều chỉnh truy vấn là bắt buộc.

Cả hai giao dịch tham gia vào bế tắc đều tranh chấp cùng một tài nguyên waitresource="KEY: 5:72057594043629568 (6234ed5bf036)"


Bắt tốt trên các chuyển đổi varchar / nvarchar. Chúng tôi sẽ làm cho các nhà phát triển sửa lỗi này; tuy nhiên, điều này dường như không có bất kỳ ảnh hưởng thực sự nào đến các phần chèn (có thể chọn / cập nhật sẽ là một câu chuyện khác). Nhưng sự đồng thuận chung dường như là nhìn xa hơn vào phần còn lại của các giao dịch.
GoodwinSQL

Như tôi đã nói đây có thể là một trong những nguyên nhân. Bế tắc là tất cả về chỉ số bị thiếu, khóa được thực hiện trong thời gian dài hơn và một số mã kém. Một loại dữ liệu không chính xác có thể chuyển đổi tìm kiếm thành quét, vui lòng đọc liên kết này làm thế nào loại dữ liệu không chính xác có thể gây ra sự cố xã hội.techet.microsoft.com/wiki/contents/articles/ Lỗi
Shanky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.