ทำไม“ เริ่มทำธุรกรรม” ก่อน“ แทรกข้อความค้นหา” ล็อคทั้งตาราง


11

ฉันใช้ SQL Server 2005 Express

ในสถานการณ์ฉันเพิ่มBegin Transactionคำสั่งก่อนINSERTคำสั่งในกระบวนงานที่เก็บไว้ เมื่อฉันเรียกใช้โพรซีเดอร์ที่เก็บไว้นี้จะล็อกทั้งตารางและการเชื่อมต่อพร้อมกันทั้งหมดแสดงการแสดงผลที่หยุดทำงานจนกระทั่งถึงเวลาที่INSERTเสร็จสิ้น

ทำไมทั้งตารางถูกล็อคและฉันจะเอาชนะปัญหานี้ใน SQL Server 2005 Express ได้อย่างไร

แก้ไข

คำค้นหามีดังนี้:

INSERT INTO <table2> SELECT * FROM <table1> WHERE table1.workCompleted = 'NO'

2
มันไม่ได้ล็อคตารางใน postgresql
Scott Marlowe

ต้องการ @RPK เพิ่มเติม ด้วยตาราง DDL และตัวอย่างของเม็ดมีดเราสามารถให้คำอธิบายที่ถูกต้องเกี่ยวกับสิ่งที่เกิดขึ้น หากไม่มีมันเราก็แค่คาดเดา
Mark Storey-Smith

คำถามนี้คลุมเครือเกินไป ฉันจะลบการอ้างอิงใด ๆ ไปยัง DBMS อื่นและ จำกัด การตอบสนองต่อ SqlServer หาก OP หรือผู้อ่านคนอื่นต้องการพูดคุยเกี่ยวกับข้อดีของแนวคิดหลักนี้ในแพลตฟอร์มอื่น ๆ เราควรให้มันกล่าวถึงหนึ่งครั้งต่อแพลตฟอร์ม เป็นอันตรายต่อการทำให้การเข้าร่วมเป็นกลุ่มคาร์ทีเซียนจะมีการสนทนาที่แตกต่างกันมากเกินไปในหน้าเดียว
jcolebrand

คำตอบ:


25

คำตอบนี้อาจพิสูจน์ได้ว่าเป็นประโยชน์กับคำถามต้นฉบับ แต่โดยหลักแล้วจะเน้นข้อมูลที่ไม่ถูกต้องในโพสต์อื่น นอกจากนี้ยังเน้นหัวข้อไร้สาระใน BOL

และตามที่ระบุไว้ในเอกสารINSERTมันจะได้รับล็อคพิเศษบนโต๊ะ วิธีเดียวที่เลือกได้กับตารางคือใช้ NOLOCK หรือตั้งค่าระดับการแยกของธุรกรรม

ส่วนที่เชื่อมโยงของสถานะ BOL:

คำสั่ง INSERT จะได้รับการล็อคเอกสิทธิ์ (X) บนโต๊ะที่ปรับเปลี่ยนและเก็บล็อกนั้นไว้จนกว่าธุรกรรมจะเสร็จสมบูรณ์ ด้วยการล็อคแบบเอกสิทธิ์ (X) ไม่มีธุรกรรมอื่นใดสามารถแก้ไขข้อมูลได้ การดำเนินการอ่านสามารถเกิดขึ้นได้เฉพาะกับการใช้คำใบ้ NOLOCK หรืออ่านระดับการแยกที่ปราศจากข้อผูกมัด สำหรับข้อมูลเพิ่มเติมโปรดดูที่ล็อคในโปรแกรมฐานข้อมูล

หมายเหตุ: ตั้งแต่ 2014-8-27 BOL ได้รับการปรับปรุงเพื่อลบข้อความที่ไม่ถูกต้องที่อ้างถึงข้างต้น

โชคดีที่มันไม่ได้เป็นอย่างนั้น หากมีการแทรกลงในตารางอย่างมากและผู้อ่านทั้งหมดจะถูกบล็อกจากตารางทั้งหมดจนกว่าธุรกรรมแทรกจะเสร็จสิ้น นั่นจะทำให้ SQL Server เป็นเซิร์ฟเวอร์ฐานข้อมูลที่มีประสิทธิภาพเช่นเดียวกับ NTFS ไม่มาก.

สามัญสำนึกแสดงให้เห็นว่ามันไม่สามารถจะเป็นอย่างนั้น แต่ขณะที่พอลแรนดัลชี้ให้เห็น " ตัวเองไม่ชอบไว้วางใจไม่มีใคร " หากคุณไม่สามารถเชื่อใจใครได้รวมถึงBOLฉันเดาว่าเราจะต้องพิสูจน์มัน

สร้างฐานข้อมูลและเติมข้อมูลตารางดัมมีหลายแถวโดยสังเกตว่า DatabaseId ส่งคืน

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

USE [master]
GO

IF EXISTS (SELECT name FROM sys.databases WHERE name = N'LockDemo')
DROP DATABASE [LockDemo]
GO

DECLARE @DataFilePath NVARCHAR(4000)
SELECT 
    @DataFilePath = SUBSTRING(physical_name, 1, CHARINDEX(N'master.mdf', LOWER(physical_name)) - 1)
FROM 
    master.sys.master_files
WHERE 
    database_id = 1 AND file_id = 1

EXEC ('
CREATE DATABASE [LockDemo] ON  PRIMARY 
( NAME = N''LockDemo'', FILENAME = N''' + @DataFilePath + N'LockDemo.mdf' + ''', SIZE = 2MB , MAXSIZE = UNLIMITED, FILEGROWTH = 2MB )
 LOG ON 
( NAME = N''LockDemo_log'', FILENAME = N''' + @DataFilePath + N'LockDemo_log.ldf' + ''', SIZE = 1MB , MAXSIZE = UNLIMITED , FILEGROWTH = 1MB )
')

GO

USE [LockDemo]
GO

SELECT DB_ID() AS DatabaseId

CREATE TABLE [dbo].[MyTable]
(
    [id] [int] IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , [filler] CHAR(4030) NOT NULL DEFAULT REPLICATE('A', 4030) 
)
GO

INSERT MyTable DEFAULT VALUES;
GO 100

ตั้งค่าการติดตาม profiler ที่จะติดตามการล็อก: ที่ได้มาและการล็อก: เหตุการณ์ที่นำออกใช้, การกรองบน ​​DatabaseId จากสคริปต์ก่อนหน้า, การตั้งค่าพา ธ สำหรับไฟล์และแจ้งให้ TraceId ส่งคืน

declare @rc int
declare @TraceID int
declare @maxfilesize BIGINT
declare @databaseid INT
DECLARE @tracefile NVARCHAR(4000)

set @maxfilesize = 5 
SET @tracefile = N'D:\Temp\LockTrace'
SET @databaseid = 9

exec @rc = sp_trace_create @TraceID output, 0, @tracefile, @maxfilesize, NULL 
if (@rc != 0) goto error

declare @on bit
set @on = 1
exec sp_trace_setevent @TraceID, 24, 32, @on
exec sp_trace_setevent @TraceID, 24, 1, @on
exec sp_trace_setevent @TraceID, 24, 57, @on
exec sp_trace_setevent @TraceID, 24, 3, @on
exec sp_trace_setevent @TraceID, 24, 51, @on
exec sp_trace_setevent @TraceID, 24, 12, @on
exec sp_trace_setevent @TraceID, 60, 32, @on
exec sp_trace_setevent @TraceID, 60, 57, @on
exec sp_trace_setevent @TraceID, 60, 3, @on
exec sp_trace_setevent @TraceID, 60, 51, @on
exec sp_trace_setevent @TraceID, 60, 12, @on
exec sp_trace_setevent @TraceID, 23, 32, @on
exec sp_trace_setevent @TraceID, 23, 1, @on
exec sp_trace_setevent @TraceID, 23, 57, @on
exec sp_trace_setevent @TraceID, 23, 3, @on
exec sp_trace_setevent @TraceID, 23, 51, @on
exec sp_trace_setevent @TraceID, 23, 12, @on

-- DatabaseId filter
exec sp_trace_setfilter @TraceID, 3, 0, 0, @databaseid

-- Set the trace status to start
exec sp_trace_setstatus @TraceID, 1

-- display trace id for future references
select TraceID=@TraceID
goto finish

error: 
select ErrorCode=@rc

finish: 
go

แทรกแถวและหยุดการติดตาม:

USE LockDemo
GO
INSERT MyTable DEFAULT VALUES
GO
EXEC sp_trace_setstatus 3, 0
EXEC sp_trace_setstatus 3, 2
GO

เปิดไฟล์ติดตามและคุณควรพบสิ่งต่อไปนี้:

หน้าต่างตัวสร้างโปรไฟล์

ลำดับของการล็อคคือ:

  1. ล็อค Intent-Exclusive บน MyTable
  2. การล็อก Intent-Exclusive บนหน้า 1: 211
  3. RangeInsert-NullResource ในรายการดัชนีคลัสเตอร์สำหรับค่าที่ถูกแทรก
  4. กุญแจล็อคพิเศษ

ล็อคจะถูกปล่อยออกมาในลำดับกลับกัน ไม่มีการล็อคแบบเอกสิทธิ์ที่ได้มาบนโต๊ะ

แต่นี่เป็นเพียงการแทรกแบทช์! นั่นไม่เหมือนกับการวิ่งสองสามหรือสิบขนาน

ใช่แล้ว. SQL Server (และเอ็นจิ้นฐานข้อมูลเชิงสัมพันธ์ใด ๆ ) ไม่มีการคาดการณ์ล่วงหน้าว่าแบทช์ใดที่อาจทำงานอยู่เมื่อประมวลผลคำสั่งและ / หรือแบทช์ดังนั้นลำดับของการได้รับการล็อกจะไม่แตกต่างกัน

ระดับการแยกที่สูงขึ้นเช่น Serializable คืออะไร

สำหรับตัวอย่างนี้โดยเฉพาะจะมีการล็อคตัวเดียวกันทุกประการ อย่าเชื่อฉันลองดูสิ!


2
ข้อมูลมาก เยี่ยมมาก @ Mark!
jcolebrand

0

ฉันไม่ได้ทำงาน T-SQL มากนัก แต่จากการอ่านเอกสาร ...

นี่คือโดยการออกแบบตามที่ระบุไว้ในการทำธุรกรรมเริ่มต้น :

ขึ้นอยู่กับการตั้งค่าระดับการแยกธุรกรรมปัจจุบันทรัพยากรจำนวนมากที่ได้รับเพื่อสนับสนุนคำสั่ง Transact-SQL ที่ออกโดยการเชื่อมต่อจะถูกล็อคโดยการทำธุรกรรมจนกว่าจะเสร็จสิ้นด้วยคำสั่ง COMMIT TRANSACTION หรือ ROLLBACK TRANSACTION

และตามที่ระบุไว้ในเอกสารINSERTมันจะได้รับล็อคพิเศษบนโต๊ะ วิธีเดียวที่เลือกได้กับตารางคือการใช้NOLOCKหรือตั้งค่าระดับการแยกของธุรกรรม


4
ไม่ได้สังเกตเห็นว่าคำสั่งที่ค่อนข้างเลวร้ายใน BOL มาก่อน การล็อคแบบเอกสิทธิ์เฉพาะบุคคลในสิ่งที่อยู่ในลำดับชั้นของทรัพยากรจะต้อง แต่มันแน่นอนที่สุดไม่ได้เสมอตาราง
Mark Storey-Smith

6
-1 สำหรับเอกสาร (ไม่ใช่ความผิดของคุณ) - มันง่ายที่จะพิสูจน์ว่านี่ไม่ใช่ความจริงในการแยกสแน๊ปช็อตดังนั้นผ้าห่ม "มักจะได้รับการล็อคเอกสิทธิ์ (X) เสมอ" ผิด ไม่แน่ใจเกี่ยวกับระดับการแยกอื่น ๆ
แจ็คบอกว่าลอง topanswers.xyz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.