I have a large (~67 million rows) name-value table that has full-text indexing on the value column (DataValue).
My question is:
If I try to run the following sql command:
ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;
GO
It runs for 1 hour 10 minutes and still does not complete on a VisitorData table that contains ~67 million rows.
My questions are:
- Why is this taking so long and not completing?
- What can I do about it?
Here are more particulars about the table:
CREATE TABLE [dbo].[VisitorData](
[VisitorID] [int] NOT NULL,
[DataName] [varchar](80) NOT NULL,
[DataValue] [nvarchar](3800) NOT NULL,
[EncryptedDataValue] [varbinary](max) NULL,
[VisitorDataID] [int] IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK_VisitorData_VisitorDataID] PRIMARY KEY CLUSTERED (
[VisitorDataID] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UNQ_VisitorData_VisitorId_DataName] UNIQUE NONCLUSTERED (
[VisitorID] ASC,
[DataName] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[VisitorData]
ADD CONSTRAINT [UNQ_VisitorData_VisitorDataID] UNIQUE NONCLUSTERED (
[VisitorDataID] ASC
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE [dbo].[VisitorData]
WITH CHECK ADD
CONSTRAINT [FK_VisitorData_Visitors] FOREIGN KEY([VisitorID])
REFERENCES [dbo].[Visitors] ([VisitorID])
GO
ALTER TABLE [dbo].[VisitorData]
CHECK CONSTRAINT [FK_VisitorData_Visitors] GO
CREATE FULLTEXT CATALOG DBName_VisitorData_Catalog WITH ACCENT_SENSITIVITY = ON
CREATE FULLTEXT INDEX ON VisitorData ( DataValue Language 1033 )
KEY INDEX UNQ_VisitorData_VisitorDataID
ON DBName_VisitorData_Catalog
WITH CHANGE_TRACKING AUTO
GO
The wait types that are occurring during the ALTER TABLE command are LCK_M_SCH_M (Schema modification), as per the query results below:
select * from sys.dm_os_waiting_tasks
waiting_task_address session_id exec_context_id wait_duration_ms wait_type resource_address blocking_task_address blocking_session_id blocking_exec_context_id resource_description
-------------------- ---------- --------------- -------------------- -------------------- ------------------ --------------------- ------------------- ------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0x0000000000B885C8 54 0 112695 LCK_M_SCH_M 0x00000000802DF600 0x000000000054E478 25 0 objectlock lockPartition=0 objid=834102012 subresource=FULL dbid=5 id=lock438a02e80 mode=IS associatedObjectId=834102012
0x0000000000B885C8 54 0 112695 LCK_M_SCH_M 0x00000000802DF600 0x00000000088AB048 23 0 objectlock lockPartition=0 objid=834102012 subresource=FULL dbid=5 id=lock438a02e80 mode=IS associatedObjectId=834102012
I am adding my comments to feedback here because they're lengthy:
As per Jason's answer below, I issued the following update instead:
ALTER TABLE VisitorData ADD NumericValue bit NULL
GO
This finally did execute as several folks have suggested in their answers, but took 29 minutes, 16 seconds!
I'm working with production servers that are running sql 2005 SP 2 (soon to be upgraded to 2008 SP2).
Martin: I did not see your comment until I did a workaround (removing the DEFAULT 0 NOT NULL part) to add that new bit column to the table. So, I couldn't run that 2nd query on the sys.dm_exec_requests table that you suggested.
With the new bit field in place in the table (as per above comment), I was able to quickly add the default value to it via the script:
ALTER TABLE VisitorData ADD
CONSTRAINT DF_VisitorData_NumericValue DEFAULT(0) FOR NumericValue;
GO
I am in the process of now setting all of the NumericValue bits in the table using a user-defined function (see below). It is in progress and taking about 1 minute per every 1 million rows in the ~68 million row table.
WITH RD_CTE (VisitorD, DataName)
AS
(
SELECT TOP 10000 VisitorD, DataName
FROM VisitorData WITH (NOLOCK)
WHERE NumericValue IS NULL
)
UPDATE VisitorData
SET NumericValue = CASE WHEN dbo.ufn_IsReallyNumeric(rd.DataValue) = 1 THEN 1 ELSE 0 END
FROM VisitorData rd WITH (NOLOCK)
INNER JOIN RD_CTE rdc WITH (NOLOCK) ON rd.VisitorD = rdc.VisitorD AND rd.DataName = rdc.DataName
GO 6800
Once that's complete, I plan to run the final schema adjustment to make that new bit column non-null:
ALTER TABLE VisitorData ALTER COLUMN NumericValue bit NOT NULL;
GO
Hopefully, this last schema update will run quickly once all values are non-null and the NumericValue default is in place.
What then concerns me is how to actually deploy these changes to a live customer site. This is an extremely lengthy process and I cannot afford to take the customer DB offline for so long - with the worst offender being the initial 29+ minute update just to add that new nullable bit column to the table.
Any thoughts on how to actually deploy this to a live website (using sql 2005 sp2 or 2008 sp 2) would be appreciated.

sys.dm_os_waiting_tasksfor that spid what wait types is it getting? – Martin Smith Feb 3 '12 at 16:48LCK_M_SCH_Mlock. Though the wait is only 2 minutes. Did you cancel it and try again? – Martin Smith Feb 3 '12 at 19:41SELECT command, wait_type,wait_time,last_wait_type FROM sys.dm_exec_requests where session_id in (23,25)show? – Martin Smith Feb 3 '12 at 20:16