Mengapa perintah ALTER TABLE sederhana begitu lama di meja dengan indeks teks lengkap?

14

Saya memiliki tabel nilai-nama besar (~ 67 juta baris) yang memiliki pengindeksan teks lengkap pada DataValuekolom.

Jika saya mencoba menjalankan perintah berikut:

ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;

Ini berjalan selama 1 jam 10 menit dan masih belum selesai pada VisitorDatatabel yang berisi ~ 67 juta baris.

  1. Mengapa ini berlangsung lama dan tidak selesai?
  2. Apa yang bisa saya lakukan?

Berikut adalah rincian tentang tabel:

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

Jenis menunggu yang terjadi selama ALTER TABLEperintah adalah LCK_M_SCH_M(modifikasi skema), sesuai hasil kueri di bawah ini:

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

Saya bekerja dengan server produksi yang menjalankan SQL Server 2005 SP 2 (segera ditingkatkan ke 2008 SP2).

BobbyR-1of4
sumber

Jawaban:

15

Skema mengubahnya membutuhkan waktu lama karena Anda menetapkan nilai default ke kolom selama perubahan dan memaksakannya dengan kolom yang tidak dapat dibatalkan, dan harus mengisi kolom untuk 60+ juta baris, yang merupakan operasi yang sangat mahal. Saya tidak yakin apa persyaratan aplikasi Anda tetapi sebuah pendekatan yang akan membuat skema berubah lebih cepat adalah menambahkannya sebagai kolom yang dapat dibatalkan tanpa nilai default dan kemudian melakukan pembaruan dalam batch untuk menetapkan 0 sebagai nilai untuk kolom. Setelah pembaruan Anda selesai, Anda dapat menerapkan perubahan skema lain untuk mengubah kolom menjadi non-nullable dan menetapkan nilai default.

Jason Cumberland
sumber
9

Pengindeksan teks lengkap, kemungkinan, tidak relevan dengan masalah Anda. Sebelum SQL Server 2012, ADD COLUMN NOT NULL DEFAULT ...ini adalah operasi offline yang harus menjalankan pembaruan dan mengisi setiap baris dengan nilai default baru dari kolom yang baru ditambahkan. Di SQL Server 2012+, operasinya jauh lebih cepat, lihat Online non-NULL dengan kolom nilai tambah di SQL Server 11 karena hanya memperbarui metadata tabel dan tidak benar-benar memperbarui baris apa pun.

Anda ALTER TABLEkemungkinan besar lambat karena update. Ingat, karena itu adalah transaksi tunggal, log yang sangat besar akan dihasilkan dan log Anda kemungkinan akan tumbuh sekarang dan terus-menerus di-zero out saat mengembang. Namun, itu mungkin juga lambat karena pertikaian biasa: pernyataan itu mungkin tidak dapat memperoleh kunci SCH-M di atas meja. Melihat di sys.dm_exec_requestsharus menunjukkan apakah ini masalahnya, wait_typedan wait_resourcekolom akan menunjukkan apakah ALTERpernyataan diblokir atau membuat kemajuan.

Remus Rusanu
sumber
0

Jawaban awalnya ditambahkan ke pertanyaan oleh penulisnya:

Sesuai jawaban Jason , saya malah menerbitkan pembaruan berikut:

ALTER TABLE VisitorData ADD NumericValue bit NULL

Ini akhirnya berhasil, tetapi butuh 29 menit, 16 detik. Operasi itu sendiri harus cukup cepat (hanya metadata) jadi saya membayangkan bahwa hampir semua waktu itu dihabiskan menunggu untuk mendapatkan LCK_M_SCH_Mkunci (modifikasi skema) yang diperlukan.

Dengan bitbidang baru di tempat, saya dapat dengan cepat menambahkan nilai default melalui skrip:

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

Saya sedang dalam proses mengatur semua NumericValuebit dalam tabel menggunakan fungsi yang ditentukan pengguna (lihat di bawah). Ini sedang berlangsung dan membutuhkan waktu sekitar 1 menit per setiap 1 juta baris dalam tabel baris ~ 68 juta.

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

Setelah selesai, saya berencana untuk menjalankan penyesuaian skema terakhir untuk membuat kolom bit baru itu menjadi nol:

ALTER TABLE VisitorData ALTER COLUMN NumericValue bit NOT NULL;

Mudah-mudahan, pembaruan skema terakhir ini akan berjalan cepat setelah semua nilai bukan nol dan NumericValuedefault sudah ada.

user126897
sumber