ถ้าฉันตารางพาร์ทิชันด้วยntext
, text
หรือimage
ประเภทข้อมูลและสร้างดัชนีบนพาร์ติชันเดียวที่มีonline = off
ไม่ว่าล็อคตารางทั้งหมดหรือเพียงแค่พาร์ทิชันในคำถาม?
ถ้าฉันตารางพาร์ทิชันด้วยntext
, text
หรือimage
ประเภทข้อมูลและสร้างดัชนีบนพาร์ติชันเดียวที่มีonline = off
ไม่ว่าล็อคตารางทั้งหมดหรือเพียงแค่พาร์ทิชันในคำถาม?
คำตอบ:
ฉันมีเวลาดูนี้และเนื่องจากฉันมีสคริปต์ตัวอย่างบางส่วนที่เขียนแล้วมันค่อนข้างง่ายที่จะตรวจสอบส่วนที่เหลือ ลองตั้งค่าแล้วดูผลลัพธ์ สิ่งนี้จะสร้างตารางและดัชนีที่แบ่งพาร์ติชันที่จำเป็น
CREATE PARTITION FUNCTION YourMom ( INT )
AS RANGE LEFT FOR VALUES ( 1000000, 2000000, 3000000, 4000000, 5000000 );
CREATE PARTITION SCHEME YourDad
AS PARTITION YourMom
ALL TO ( [PRIMARY] );
CREATE TABLE dbo.YourAuntDebbie
(
Id INT,
StopUsingDeprecatedDataTypes NTEXT
) ON YourDad (Id);
DECLARE @counter INT = 1;
WHILE @counter < 6
BEGIN
RAISERROR('Run number: %d', 0, 1, @counter) WITH NOWAIT;
INSERT dbo.YourAuntDebbie WITH ( TABLOCK ) ( Id, StopUsingDeprecatedDataTypes )
SELECT TOP 1000000 x.n + CASE WHEN @counter = 1 THEN 0
WHEN @counter = 2 THEN 1000000
WHEN @counter = 3 THEN 2000000
WHEN @counter = 4 THEN 3000000
WHEN @counter = 5 THEN 4000000
ELSE 0
END,
REPLICATE(N'A', x.n % 10000)
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY @@ROWCOUNT ) AS n
FROM sys.messages AS m
CROSS JOIN sys.messages AS m2 ) AS x;
SET @counter += 1;
END;
CREATE CLUSTERED INDEX ix_whatever
ON dbo.YourAuntDebbie ( Id ) ON YourDad(Id);
นั่นให้พาร์ติชั่น 5 อันที่มี 1 ล้านแถวและพาร์ทิชันว่างหนึ่งอัน
SELECT OBJECT_NAME(p.object_id) AS table_name, p.partition_number, p.rows
FROM sys.partitions AS p
WHERE p.object_id = OBJECT_ID('dbo.YourAuntDebbie');
ตารางแฟนซี:
+----------------+------------------+---------+
| table_name | partition_number | rows |
+----------------+------------------+---------+
| YourAuntDebbie | 1 | 1000000 |
| YourAuntDebbie | 2 | 1000000 |
| YourAuntDebbie | 3 | 1000000 |
| YourAuntDebbie | 4 | 1000000 |
| YourAuntDebbie | 5 | 1000000 |
| YourAuntDebbie | 6 | 0 |
+----------------+------------------+---------+
นี่คือเซสชั่น XE ที่ฉันใช้เพื่อดูว่าการล็อกดัชนีที่สร้างใหม่ต้องการอะไร:
CREATE EVENT SESSION Locks
ON SERVER
ADD EVENT sqlserver.lock_acquired
( SET collect_resource_description = ( 1 )
ACTION ( sqlserver.sql_text )
WHERE ( sqlserver.equal_i_sql_unicode_string(sqlserver.database_name, N'Crap')
AND package0.equal_uint64(sqlserver.session_id, ( 61 )))),
ADD EVENT sqlserver.lock_released
( SET collect_resource_description = ( 1 )
ACTION ( sqlserver.sql_text )
WHERE ( sqlserver.database_name = N'Crap'
AND sqlserver.session_id = ( 61 )))
ADD TARGET package0.event_file
( SET filename = N'c:\temp\Locks' )
WITH ( MAX_MEMORY = 4096KB,
EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS,
MAX_DISPATCH_LATENCY = 30 SECONDS,
MAX_EVENT_SIZE = 0KB,
MEMORY_PARTITION_MODE = NONE,
TRACK_CAUSALITY = ON,
STARTUP_STATE = OFF );
GO
เมื่อถึงตอนนั้นฉันสามารถสร้างพาร์ติชันขึ้นใหม่แล้วขุดลงใน XE
ALTER EVENT SESSION Locks ON SERVER STATE = START;
ALTER INDEX ix_whatever ON dbo.YourAuntDebbie REBUILD PARTITION = 1 WITH (ONLINE = OFF);
GO
ALTER INDEX ix_whatever ON dbo.YourAuntDebbie REBUILD PARTITION = 2 WITH (ONLINE = OFF);
GO
ALTER INDEX ix_whatever ON dbo.YourAuntDebbie REBUILD PARTITION = 3 WITH (ONLINE = OFF);
GO
ALTER INDEX ix_whatever ON dbo.YourAuntDebbie REBUILD PARTITION = 4 WITH (ONLINE = OFF);
GO
ALTER INDEX ix_whatever ON dbo.YourAuntDebbie REBUILD PARTITION = 5 WITH (ONLINE = OFF);
GO
ALTER INDEX ix_whatever ON dbo.YourAuntDebbie REBUILD PARTITION = 6 WITH (ONLINE = OFF);
GO
ALTER EVENT SESSION Locks ON SERVER STATE = STOP;
ตอนนี้ฉันจะวางชิ้นส่วนย่อยของเหตุการณ์ XE ไว้ท้ายเพราะมันน่าเกลียดและไม่มีเหตุผลที่จะทำให้ทุกคนนั่งลงเพื่อดูผลลัพธ์ ฉันจะใช้ผลลัพธ์ของพาร์ติชันแรกเป็นตัวอย่าง แต่พวกเขาจะเหมือนกันในทั้ง 6 พาร์ติชันแม้กระทั่งพาร์ติชันที่ว่างเปล่า
ฉัน จำกัด ผลลัพธ์ของการอัปเดตเฉพาะล็อคระดับวัตถุเท่านั้น นี่เป็นสิ่งเดียวที่เราใส่ใจ
+---------------+-------------------------+----------------+--------------+-------+------------------+--------+
| EventName | EventDate | ObjectName | ResourceType | Mode | PARTITIONREBUILT | Events |
+---------------+-------------------------+----------------+--------------+-------+------------------+--------+
| lock_acquired | 2017-10-03 13:21:14.554 | YourAuntDebbie | OBJECT | SCH_M | PARTITION = 1 | 1 |
| lock_acquired | 2017-10-03 13:21:14.554 | YourAuntDebbie | OBJECT | SCH_S | PARTITION = 1 | 1 |
| lock_released | 2017-10-03 13:21:14.554 | YourAuntDebbie | OBJECT | SCH_S | PARTITION = 1 | 1 |
| lock_acquired | 2017-10-03 13:21:14.603 | YourAuntDebbie | OBJECT | S | PARTITION = 1 | 6 |
| lock_acquired | 2017-10-03 13:21:14.603 | YourAuntDebbie | OBJECT | SCH_S | PARTITION = 1 | 30 |
| lock_released | 2017-10-03 13:21:14.603 | YourAuntDebbie | OBJECT | SCH_S | PARTITION = 1 | 24 |
| lock_released | 2017-10-03 13:21:14.867 | YourAuntDebbie | OBJECT | SCH_M | PARTITION = 1 | 1 |
+---------------+-------------------------+----------------+--------------+-------+------------------+--------+
จากสิ่งที่ผมสามารถบอกได้สำหรับแต่ละพาร์ทิชันที่SCH-M
ล็อคนำออกมาที่จุดเริ่มต้นของดัชนีสร้างและปล่อยออกมาในท้ายที่สุดบนโต๊ะ
ตัวอย่างเช่นถ้าฉันเรียกใช้พาร์ติชันเดียวที่สร้างใหม่ในการทำธุรกรรม:
BEGIN TRAN
ALTER INDEX ix_whatever ON dbo.YourAuntDebbie REBUILD PARTITION = 1 WITH (ONLINE = OFF);
--ROLLBACK
จากนั้นในหน้าต่าง SSMS อื่น:
SELECT *
FROM dbo.YourAuntDebbie AS yad
WHERE yad.Id = 6000000
AND 1 = (SELECT 1)
การเลือกถูกบล็อกจนกว่าฉันจะฆ่าการสร้างใหม่ เมื่อเสร็จสิ้นแผนแบบสอบถามจะแสดงการกำจัดพาร์ติชันที่เกิดขึ้นดังนั้นเฉพาะพาร์ติชัน 1 ที่ถูกสร้างขึ้นมาใหม่จะปรากฏขึ้นเพื่อให้มีผลกับทั้งตาราง
หวังว่านี่จะช่วยได้!
ตอนนี้นี่คือรหัสการทำลายเซสชัน XE อันยิ่งใหญ่:
CREATE TABLE #Locks
(
ID INT IDENTITY(1, 1) NOT NULL PRIMARY KEY CLUSTERED,
WaitsXML XML
);
INSERT #Locks
( WaitsXML )
SELECT CONVERT(XML, event_data) AS TargetData
FROM sys.fn_xe_file_target_read_file( 'c:\temp\Locks*.xel', NULL, NULL, NULL);
WITH locks
AS ( SELECT l.WaitsXML.value('(/event/@name)[1]', 'VARCHAR(128)') AS EventName,
l.WaitsXML.value('(/event/@timestamp)[1]', 'DATETIME2(3)') AS EventDate,
l.WaitsXML.value('(event/data[@name="object_id"]/value)[1]', 'NUMERIC') AS ObjectId,
l.WaitsXML.value('(event/data[@name="resource_type"]/text)[1]', 'VARCHAR(128)') AS ResourceType,
l.WaitsXML.value('(event/data[@name="mode"]/text)[1]', 'VARCHAR(128)') AS Mode,
l.WaitsXML.value('(event/action[@name="sql_text"]/value)[1]', 'VARCHAR(128)') AS SQLText,
l.WaitsXML
FROM #Locks AS l )
SELECT locks.EventName,
locks.EventDate,
ISNULL(OBJECT_NAME(locks.ObjectId), 'Unknown') AS ObjectName,
locks.ResourceType,
locks.Mode,
SUBSTRING(
locks.SQLText,
CHARINDEX('PARTITION', locks.SQLText),
CHARINDEX('WITH', locks.SQLText, CHARINDEX('PARTITION', locks.SQLText))
- CHARINDEX('PARTITION', locks.SQLText)) AS PARTITIONREBUILT,
COUNT(*) AS Events
FROM locks
WHERE OBJECT_NAME(locks.ObjectId) = 'YourAuntDebbie'
--OR OBJECT_NAME(locks.ObjectId) IS NULL
GROUP BY ISNULL(OBJECT_NAME(locks.ObjectId), 'Unknown'),
SUBSTRING(
locks.SQLText,
CHARINDEX('PARTITION', locks.SQLText),
CHARINDEX('WITH', locks.SQLText, CHARINDEX('PARTITION', locks.SQLText))
- CHARINDEX('PARTITION', locks.SQLText)),
locks.EventName,
locks.EventDate,
locks.ResourceType,
locks.Mode
ORDER BY locks.EventDate;