Here is another common question appeared in forums, how to change the data type of column, specifically a large table. If you search for it, the most common one is, handling this with a new column (which is my 3rd way in the code). However, situation to situation, things can be different, hence tested few ways of changing the type with a table that contains 7 millions records.
Here are 3 ways I tried with. The code uses 3 tables called dbo.Sales_1, dbo.Sales_2, and dbo.Sales_3. The structure and the number of records are same for all 3 tables. Here is the test I did.
-- Method 1 -- ======== -- Check the fragmentation of the table SELECT * FROM sys.dm_db_index_physical_stats(db_id(), object_id('dbo.Sales_1'), null, null, 'detailed'); -- Result -- External Fragmentation - 0.3% (Good) -- Internal Fragmentation - 98% (Good) -- Changing the column type of Product key from int to bigint ALTER TABLE dbo.Sales_1 ALTER COLUMN ProductKey bigint not null; -- Result -- Time spent: 4:47 -- Checking fragmentation again SELECT * FROM sys.dm_db_index_physical_stats(db_id(), object_id('dbo.Sales_1'), null, null, 'detailed'); -- Result -- External Fragmentation - 99% (Bad) -- Internal Fragmentation - 51% (Bad) -- Rebulding the index ALTER INDEX PK__Sales_1 ON dbo.Sales_1 REBUILD; -- Result -- Time spent: 3:43 -- ** -- Total time spent: 8:30 -- ** -- Method 2 -- ======== -- Check the fragmentation of the table SELECT * FROM sys.dm_db_index_physical_stats(db_id(), object_id('dbo.Sales_2'), null, null, 'detailed'); -- Result -- External Fragmentation - 0.3% (Good) -- Internal Fragmentation - 98% (Good) -- Rebuilding the index with filfactor 80. ALTER INDEX PK__Sales_2 ON dbo.Sales_2 REBUILD WITH (FILLFACTOR = 80); GO -- Result -- Time spent: 1:38 -- Changing the column type of Product key from int to bigint ALTER TABLE dbo.Sales_2 ALTER COLUMN ProductKey bigint not null -- Result -- Time spent: 1:13 -- Check for fragmentation SELECT * FROM sys.dm_db_index_physical_stats(db_id(), object_id('dbo.Sales_2'), null, null, 'detailed'); -- Result -- External Fragmentation - 0.1% (Good) -- Internal Fragmentation - 85% (Good) -- ** -- Total time spent: 2:51 -- ** -- Method 3 -- ======== -- Check the fragmentation of the table SELECT * FROM sys.dm_db_index_physical_stats(db_id(), object_id('dbo.Sales_3'), null, null, 'detailed'); -- Result -- External Fragmentation - 0.3% (Good) -- Internal Fragmentation - 98% (Good) -- Add a new column with required data type: bigint -- Setting it as a nullable column ALTER TABLE dbo.Sales_3 ADD NewProductKey bigint null -- Changing the recovery model ALTER DATABASE TestDatabase SET RECOVERY Bulk_Logged; -- Updating the new column with old column value DECLARE @Count int = 1 WHILE (@Count != 0) BEGIN UPDATE TOP (500000) dbo.Sales_3 WITH (TABLOCK) SET NewProductKey = ProductKey WHERE NewProductKey IS NULL SET @Count = @@ROWCOUNT END -- Result -- Time spent: 1:23 -- Drop the old column ALTER TABLE dbo.Sales_3 DROP COLUMN ProductKey -- Rename the new column as old column sp_rename 'dbo.Sales_3.NewProductKey', 'ProductKey', 'COLUMN'; -- Alter the current column as non-nullable ALTER TABLE dbo.Sales_3 ALTER COLUMN ProductKey bigint NOT NULL -- Result -- Time spent: 0.03 -- Check the fragmentation of the table SELECT * FROM sys.dm_db_index_physical_stats(db_id(), object_id('dbo.Sales_3'), null, null, 'detailed'); -- Result -- External Fragmentation - 99% (Bad) -- Internal Fragmentation - 51% (Bad) ALTER INDEX PK__Sales_3 ON dbo.Sales_4 REBUILD; -- Result -- Time spent: 2:55 -- Change back the recovery model ALTER DATABASE TestDatabase SET RECOVERY Full; -- ** -- Total time spent: 4:21 -- **
Here is the summary of it;
Method | Time Spent | Comments |
---|---|---|
1 - Just alter the column | 8:30 | Takes long time |
2 - Alter the column with fill-factor | 2:51 | Fastest, Probably the best |
3 - With a new column | 4:21 | Good, but need more extra work |
My preference is for the highlighted one as it gives the best performance and I do not see any issue with it.
No comments:
Post a Comment