เหตุใดคำสั่ง ALTER TABLE แบบธรรมดาจึงใช้เวลานานในตารางที่มีดัชนีข้อความแบบเต็ม?


14

ฉันมีตารางชื่อมูลค่าขนาดใหญ่ (~ 67 ล้านแถว) ที่มีการจัดทำดัชนีข้อความแบบเต็มในDataValueคอลัมน์

ถ้าฉันพยายามเรียกใช้คำสั่งต่อไปนี้:

ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;

มันทำงานเป็นเวลา 1 ชั่วโมง 10 นาทีและยังไม่เสร็จสมบูรณ์ในVisitorDataตารางที่มีประมาณ 67 ล้านแถว

  1. ทำไมการดำเนินการนี้ใช้เวลานานและไม่เสร็จสมบูรณ์
  2. ฉันจะทำอะไรได้บ้าง

นี่คือรายละเอียดเพิ่มเติมเกี่ยวกับตาราง:

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

ชนิดการรอที่เกิดขึ้นระหว่างALTER TABLEคำสั่งคือLCK_M_SCH_M(การแก้ไข schema) ตามผลลัพธ์ของแบบสอบถามด้านล่าง:

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

ฉันทำงานกับเซิร์ฟเวอร์ที่ใช้งานจริงที่กำลังเรียกใช้ SQL Server 2005 SP 2 (เร็ว ๆ นี้จะได้รับการอัพเกรดเป็น 2008 SP2)

คำตอบ:


16

สคีมาเปลี่ยนแปลงใช้เวลานานมากเนื่องจากคุณกำลังกำหนดค่าเริ่มต้นให้กับคอลัมน์ในระหว่างการเปลี่ยนแปลงและการบังคับใช้นั้นด้วยคอลัมน์ที่ไม่เป็นโมฆะและต้องมีการเติมคอลัมน์สำหรับ 60 ล้านแถวซึ่งเป็นการดำเนินการที่มีราคาแพงอย่างไม่น่าเชื่อ ฉันไม่แน่ใจว่าข้อกำหนดของแอปพลิเคชันของคุณคืออะไร แต่วิธีการที่จะทำให้การเปลี่ยนแปลงสคีมาเร็วขึ้นคือการเพิ่มเข้าไปในคอลัมน์ที่ไม่มีค่าโดยไม่มีค่าเริ่มต้นจากนั้นทำการอัปเดตเป็นกลุ่มเพื่อกำหนด 0 เป็นค่าสำหรับคอลัมน์ หลังจากเสร็จสิ้นการอัพเดตของคุณคุณสามารถใช้การเปลี่ยนแปลงสคีมาอีกครั้งเพื่อเปลี่ยนคอลัมน์เป็นไม่สามารถลบล้างได้และกำหนดค่าเริ่มต้น


9

การทำดัชนีข้อความแบบเต็มมีแนวโน้มว่าไม่เกี่ยวข้องกับปัญหาของคุณ ก่อนหน้า SQL Server 2012 ADD COLUMN NOT NULL DEFAULT ...เป็นการดำเนินการออฟไลน์ที่ต้องเรียกใช้การอัปเดตและเติมข้อมูลแต่ละแถวด้วยค่าเริ่มต้นใหม่ของคอลัมน์ที่เพิ่มใหม่ ใน SQL Server 2012+ การดำเนินการจะเร็วขึ้นมากดูออนไลน์ที่ไม่ใช่ค่า NULL ด้วยคอลัมน์ค่าที่เพิ่มใน SQL Server 11เนื่องจากจะอัปเดตข้อมูลเมตาของตารางเท่านั้นและไม่ได้อัพเดตแถวใด ๆ

คุณALTER TABLEน่าจะช้าเพราะการอัพเดท โปรดจำไว้ว่าเนื่องจากเป็นธุรกรรมเดียวบันทึกขนาดใหญ่จะถูกสร้างขึ้นและบันทึกของคุณมีแนวโน้มที่จะเติบโตในขณะนี้และไม่มีการแก้ไขศูนย์ตลอดเวลาเมื่อขยาย อย่างไรก็ตามมันอาจจะช้าเพราะความขัดแย้งทั่วไป: คำสั่งอาจไม่สามารถรับล็อค SCH-M บนโต๊ะ ดูที่sys.dm_exec_requestsควรแสดงว่าเป็นกรณีนี้หรือไม่wait_typeและwait_resourceคอลัมน์จะระบุว่าALTERคำสั่งนั้นถูกบล็อกหรือกำลังดำเนินการอยู่


0

คำตอบเดิมที่เพิ่มไปยังคำถามโดยผู้เขียน:

ตามคำตอบของ Jasonฉันออกการปรับปรุงต่อไปนี้แทน:

ALTER TABLE VisitorData ADD NumericValue bit NULL

ในที่สุดนี้ก็ดำเนินการ แต่ใช้เวลา 29 นาที, 16 วินาที การดำเนินการเองควรจะค่อนข้างรวดเร็ว (ข้อมูลเมตาเท่านั้น) ดังนั้นฉันจึงจินตนาการว่าเกือบตลอดเวลานั้นใช้เวลาเพื่อรอLCK_M_SCH_Mการล็อค (การปรับเปลี่ยนสคีมา) ที่จำเป็น

ด้วยbitฟิลด์ใหม่ที่เข้ามาฉันสามารถเพิ่มค่าเริ่มต้นอย่างรวดเร็วผ่านสคริปต์:

ALTER TABLE VisitorData ADD
CONSTRAINT DF_VisitorData_NumericValue DEFAULT(0) FOR NumericValue;

ฉันอยู่ในกระบวนการของการตั้งค่าNumericValueบิตทั้งหมดในตารางโดยใช้ฟังก์ชั่นที่ผู้ใช้กำหนด (ดูด้านล่าง) กำลังดำเนินการและใช้เวลาประมาณ 1 นาทีต่อทุก ๆ 1 ล้านแถวในตาราง ~ 68 ล้านแถว

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

เมื่อเสร็จแล้วฉันวางแผนที่จะรันการปรับสกีมาขั้นสุดท้ายเพื่อสร้างคอลัมน์บิตใหม่ที่ไม่ใช่ค่าว่าง:

ALTER TABLE VisitorData ALTER COLUMN NumericValue bit NOT NULL;

หวังว่าการอัปเดตสคีมาครั้งสุดท้ายนี้จะทำงานได้อย่างรวดเร็วเมื่อค่าทั้งหมดไม่เป็นโมฆะและมีNumericValueค่าเริ่มต้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.