patternsqlModerate
Offline Index Rebuild on a Partitioned Table
Viewed 0 times
rebuildofflineindexpartitionedtable
Problem
If I partition a table with
ntext, text or image datatypes and rebuild an index on a single partition with online = off, does that lock the whole table or just the partition in question?Solution
I had some time to look at this, and since I already had some of the demo scripts written, it was pretty easy to check on the rest. Let's do the setup, then look at the results. This will create the necessary partitioned table and index.
That gives me 5 partitions with 1 million rows, and one empty partition.
Fancy table:
Here's the XE session I'm using to see which locks the index rebuilds need:
With that in place, I can rebuild my partitions, and then dig into XE.
Now, I'm gonna put the XE event shredding stuff at the end, because it's pretty ugly, and there's no reason to make everyone sit through that to see the results. I'm going to use the first partition's results as an example, but they're just about identical across all 6 partitions, even the empty one.
I'm limiting the results of the update to only the object level locks. These are the only ones we care about.
```
+---------------+-------------------------+----------------+--------------+-------+------------------+--------+
| 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 |
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);That gives me 5 partitions with 1 million rows, and one empty partition.
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');Fancy table:
+----------------+------------------+---------+
| table_name | partition_number | rows |
+----------------+------------------+---------+
| YourAuntDebbie | 1 | 1000000 |
| YourAuntDebbie | 2 | 1000000 |
| YourAuntDebbie | 3 | 1000000 |
| YourAuntDebbie | 4 | 1000000 |
| YourAuntDebbie | 5 | 1000000 |
| YourAuntDebbie | 6 | 0 |
+----------------+------------------+---------+Here's the XE session I'm using to see which locks the index rebuilds need:
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 );
GOWith that in place, I can rebuild my partitions, and then dig into 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;Now, I'm gonna put the XE event shredding stuff at the end, because it's pretty ugly, and there's no reason to make everyone sit through that to see the results. I'm going to use the first partition's results as an example, but they're just about identical across all 6 partitions, even the empty one.
I'm limiting the results of the update to only the object level locks. These are the only ones we care about.
```
+---------------+-------------------------+----------------+--------------+-------+------------------+--------+
| 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 |
Code Snippets
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);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 |
+----------------+------------------+---------+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 );
GOALTER 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;Context
StackExchange Database Administrators Q#186420, answer score: 13
Revisions (0)
No revisions yet.