Basit ALTER TABLE komutu neden tam metin dizinli tabloda bu kadar uzun sürüyor?


14

DataValueSütunda tam metin dizinleme olan büyük (~ 67 milyon satır) bir ad-değer tablosu var .

Aşağıdaki komutu çalıştırmayı denersem:

ALTER TABLE VisitorData ADD NumericValue bit DEFAULT 0 NOT NULL;

1 saat 10 dakika sürer ve hala VisitorData~ 67 milyon satır içeren bir tabloda tamamlanmaz .

  1. Bu neden bu kadar uzun sürüyor ve tamamlanmıyor?
  2. Bu konuda ne yapabilirim?

İşte tablo hakkında daha fazla bilgi:

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 TABLEKomut sırasında oluşan bekleme türleri, LCK_M_SCH_Maşağıdaki sorgu sonuçlarına göre (şema değişikliği) şeklindedir:

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 (yakında 2008 SP2'ye yükseltilecek) çalıştıran üretim sunucuları ile çalışıyorum.

Yanıtlar:


16

Şema değişikliği çok uzun sürüyor çünkü değişiklik sırasında sütuna varsayılan bir değer atadığınız ve null edilemeyen bir sütunla bunu uyguladığınız ve sütunu 60 milyondan fazla satır için doldurmanız gerekiyor, bu inanılmaz pahalı bir işlem. Uygulama gereksinimlerinizin ne olduğundan emin değilim, ancak şemanın daha hızlı değişmesini sağlayacak bir yaklaşım, varsayılan değeri olmayan boş bir sütun olarak eklemek ve sonra sütun için 0 olarak atamak için toplu olarak bir güncelleme yapmaktır. Güncellemeniz tamamlandıktan sonra, sütunu boş bırakılamaz olarak değiştirmek ve varsayılan değeri atamak için başka bir şema değişikliği uygulayabilirsiniz.


9

Tam metin dizine ekleme, büyük olasılıkla sorununuzla ilgili değildir. SQL Server 2012'den önce ADD COLUMN NOT NULL DEFAULT ..., bir güncelleştirme çalıştırmak ve her satırı yeni eklenen sütunun yeni varsayılan değeriyle doldurmak zorunda olan çevrimdışı bir işlemdir. SQL Server 2012 ve sonraki sürümlerde, işlem çok daha hızlıdır, SQL Server 11'de yalnızca tablonun meta verilerini güncellediğinden ve gerçekte herhangi bir satırı güncellemediğinden , SQL Server 11'deki NULL olmayan çevrimiçi sütun ekleme bölümüne bakın .

Sizin ALTER TABLEçünkü güncelleme büyük olasılıkla yavaştır. Unutmayın, bu tek bir işlem olduğundan, büyük bir günlük oluşturulacak ve günlüğünüz büyük olasılıkla şimdi büyüyor ve genişledikçe sürekli sıfırlanıyor. Bununla birlikte, sıradan çekişme nedeniyle de yavaş olabilir: ifade, tablodaki SCH-M kilidini alamayabilir. Bakıldığında sys.dm_exec_requestsdurumun böyle olup olmadığını göstermeli ve wait_typeve wait_resourcesütunları ALTERifadenin engellenip engellenmediğini veya ilerleme kaydedip göstermediğini gösterecektir .


0

Yanıt aslen soruya yazarı tarafından eklendi:

Gereğince Jason'ın cevap , bunun yerine aşağıdaki güncelleştirmeyi yayınladı:

ALTER TABLE VisitorData ADD NumericValue bit NULL

Bu nihayet yürütüldü, ancak 29 dakika 16 saniye sürdü. İşlemin kendisi oldukça hızlı olmalıdır (yalnızca meta veriler), bu yüzden neredeyse tüm zamanların gerekli LCK_M_SCH_M(şema değişikliği) kilidini almak için harcanarak harcandığını hayal ediyorum .

bitYerinde yeni alan ile, hızlı bir şekilde komut dosyası üzerinden varsayılan değeri eklemek mümkün oldu:

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

Şu anda NumericValuetablodaki tüm bitleri kullanıcı tanımlı bir işlev kullanarak ayarlama sürecindeyim (aşağıya bakın). Devam ediyor ve ~ 68 milyon sıra tablosunda her 1 milyon satırda bir yaklaşık 1 dakika sürüyor.

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

Bu tamamlandığında, yeni bit sütununu null yapmak için son şema ayarlamasını çalıştırmayı planlıyorum:

ALTER TABLE VisitorData ALTER COLUMN NumericValue bit NOT NULL;

İnşallah, bu son şema güncellemesi, tüm değerler null olmadığında ve NumericValuevarsayılan ayar yerinde olduğunda hızlı bir şekilde çalışır .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.