Câu trả lời:
Tôi đã có một thời gian để xem xét điều này, và vì tôi đã có một số kịch bản demo được viết, nên khá dễ dàng để kiểm tra phần còn lại. Hãy thiết lập, sau đó nhìn vào kết quả. Điều này sẽ tạo ra bảng và chỉ mục phân vùng cần thiết.
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);
Điều đó mang lại cho tôi 5 phân vùng với 1 triệu hàng và một phân vùng trống.
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');
Bảng ưa thích:
+----------------+------------------+---------+
| table_name | partition_number | rows |
+----------------+------------------+---------+
| YourAuntDebbie | 1 | 1000000 |
| YourAuntDebbie | 2 | 1000000 |
| YourAuntDebbie | 3 | 1000000 |
| YourAuntDebbie | 4 | 1000000 |
| YourAuntDebbie | 5 | 1000000 |
| YourAuntDebbie | 6 | 0 |
+----------------+------------------+---------+
Đây là phiên XE tôi đang sử dụng để xem khóa nào mà chỉ mục xây dựng lại cần:
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
Với vị trí đó, tôi có thể xây dựng lại các phân vùng của mình và sau đó đào sâu vào 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;
Bây giờ, tôi sẽ đặt sự kiện XE xé vụn vào cuối, bởi vì nó khá xấu xí, và không có lý do gì để khiến mọi người ngồi đó để xem kết quả. Tôi sẽ sử dụng kết quả của phân vùng đầu tiên làm ví dụ, nhưng chúng chỉ giống hệt nhau trên tất cả 6 phân vùng, thậm chí là phân vùng trống.
Tôi giới hạn kết quả của bản cập nhật chỉ với các khóa cấp đối tượng. Đây là những người duy nhất chúng tôi quan tâm.
+---------------+-------------------------+----------------+--------------+-------+------------------+--------+
| 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 |
+---------------+-------------------------+----------------+--------------+-------+------------------+--------+
Từ những gì tôi có thể nói, đối với mỗi phân vùng , một SCH-M
khóa được lấy ra khi bắt đầu xây dựng lại chỉ mục và được phát hành vào cuối BẢNG .
Ví dụ: nếu tôi chạy một phân vùng duy nhất được xây dựng lại trong một giao dịch:
BEGIN TRAN
ALTER INDEX ix_whatever ON dbo.YourAuntDebbie REBUILD PARTITION = 1 WITH (ONLINE = OFF);
--ROLLBACK
Và sau đó trong một cửa sổ SSMS khác:
SELECT *
FROM dbo.YourAuntDebbie AS yad
WHERE yad.Id = 6000000
AND 1 = (SELECT 1)
Việc chọn bị chặn cho đến khi tôi giết việc xây dựng lại. Khi kết thúc, kế hoạch truy vấn hiển thị loại bỏ phân vùng xảy ra , do đó, chỉ phân vùng 1 được xây dựng lại xuất hiện để tạo hiệu ứng cho toàn bộ bảng.
Hi vọng điêu nay co ich!
Bây giờ đây là mã băm nhỏ phiên XE tuyệt vời:
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;