Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

T-SQL Selasa #65 :Mengajarkan Sesuatu yang Baru

T-SQL Tuesday bulan ini dipandu oleh Mike Donnelly (@SQLMD), dan dia merangkum topiknya sebagai berikut:

Topik bulan ini lurus ke depan, tapi sangat terbuka berakhir. Anda harus mempelajari sesuatu yang baru dan kemudian menulis posting blog yang menjelaskannya.

Nah, sejak Mike mengumumkan topiknya, saya tidak benar-benar berangkat untuk mempelajari sesuatu yang baru, dan saat akhir pekan mendekat dan saya tahu Senin akan menyerang saya dengan tugas juri, saya pikir saya harus duduk di kursi ini. keluar bulan.

Kemudian, Martin Smith mengajari saya sesuatu yang tidak pernah saya ketahui, atau sudah lama saya ketahui tetapi telah saya lupakan (terkadang Anda tidak mengetahui apa yang tidak Anda ketahui, dan terkadang Anda tidak dapat mengingat apa yang tidak pernah Anda ketahui dan apa yang tidak dapat Anda ingat). ingat). Ingatan saya adalah bahwa mengubah kolom dari NOT NULL ke NULL harus menjadi operasi metadata saja, dengan menulis ke halaman mana pun ditunda hingga halaman itu diperbarui karena alasan lain, karena NULL bitmap tidak perlu ada sampai setidaknya satu baris bisa menjadi NULL .

Pada postingan yang sama, @ypercube juga mengingatkan saya pada kutipan terkait dari Books Online (salah ketik dan semuanya):

Mengubah kolom dari NOT NULL ke NULL tidak didukung sebagai operasi online ketika kolom yang diubah adalah referensi oleh indeks nonclustered.

"Bukan operasi online" dapat diartikan sebagai "bukan operasi metadata saja" – artinya ini sebenarnya operasi ukuran data (semakin besar indeks Anda, semakin lama waktu yang dibutuhkan).

Saya mulai membuktikan ini dengan eksperimen yang cukup sederhana (tetapi panjang) terhadap kolom target tertentu untuk mengonversi dari NOT NULL ke NULL . Saya akan membuat 3 tabel, semua dengan kunci utama berkerumun, tetapi masing-masing dengan indeks non-berkelompok yang berbeda. Satu akan memiliki kolom target sebagai kolom kunci, yang kedua sebagai INCLUDE kolom, dan yang ketiga tidak akan mereferensikan kolom target sama sekali.

Berikut adalah tabel saya dan bagaimana saya mengisinya:

CREATE TABLE dbo.test1
(
  a INT NOT NULL, b INT NOT NULL, c BIGINT NOT NULL,
  CONSTRAINT pk_t1 PRIMARY KEY (a,b)
);
GO
CREATE NONCLUSTERED INDEX ix1 ON dbo.test1(b,c);
GO
 
CREATE TABLE dbo.test2
(
  a INT NOT NULL, b INT NOT NULL, c BIGINT NOT NULL,
  CONSTRAINT pk_t2 PRIMARY KEY (a,b)
);
GO
CREATE NONCLUSTERED INDEX ix2 ON dbo.test2(b) INCLUDE(c);
GO
 
CREATE TABLE dbo.test3
(
  a INT NOT NULL, b INT NOT NULL, c BIGINT NOT NULL,
  CONSTRAINT pk_t3 PRIMARY KEY (a,b)
);
GO
CREATE NONCLUSTERED INDEX ix3 ON dbo.test3(b);
GO
 
INSERT dbo.test1(a,b,c) -- repeat for test2 / test3
  SELECT n1, n2, ABS(n2)-ABS(n1)
  FROM 
  (
    SELECT TOP (100000) s1.[object_id], s2.[object_id]
      FROM master.sys.all_objects AS s1
      CROSS JOIN master.sys.all_objects AS s2
      GROUP BY s1.[object_id], s2.[object_id]
  ) AS n(n1, n2);

Setiap tabel memiliki 100.000 baris, indeks yang dikelompokkan memiliki 310 halaman, dan indeks yang tidak dikelompokkan memiliki 272 halaman (test1 dan test2 ) atau 174 halaman (test3 ). (Nilai-nilai ini mudah diperoleh dari sys.dm_db_index_physical_stats .)

Selanjutnya, saya membutuhkan cara sederhana untuk menangkap operasi yang dicatat di tingkat halaman – saya memilih sys.fn_dblog() , meskipun saya bisa menggali lebih dalam dan melihat halaman secara langsung. Saya tidak repot-repot mengotak-atik nilai LSN untuk diteruskan ke fungsi, karena saya tidak menjalankan ini dalam produksi dan tidak terlalu peduli dengan kinerja, jadi setelah tes saya hanya membuang hasil fungsi, tidak termasuk data apa pun yang telah dicatat sebelum ALTER TABLE operasi.

-- establish an exclusion set
SELECT * INTO #x FROM sys.fn_dblog(NULL, NULL);

Sekarang saya dapat menjalankan pengujian saya, yang jauh lebih sederhana daripada penyiapannya.

ALTER TABLE dbo.test1 ALTER COLUMN c BIGINT NULL;
 
ALTER TABLE dbo.test2 ALTER COLUMN c BIGINT NULL;
 
ALTER TABLE dbo.test3 ALTER COLUMN c BIGINT NULL;

Sekarang saya dapat memeriksa operasi yang dicatat dalam setiap kasus:

SELECT AllocUnitName, [Operation], Context, c = COUNT(*) 
  FROM 
  (
    SELECT * FROM sys.fn_dblog(NULL, NULL)
    WHERE [Operation] = N'LOP_FORMAT_PAGE'
      AND AllocUnitName LIKE N'dbo.test%'
    EXCEPT 
    SELECT * FROM #x
  ) AS x
  GROUP BY AllocUnitName, [Operation], Context
  ORDER BY AllocUnitName, [Operation], Context;

Hasilnya tampaknya menunjukkan bahwa setiap halaman daun dari indeks non-clustered disentuh untuk kasus di mana kolom target disebutkan dalam indeks dengan cara apa pun, tetapi tidak ada operasi seperti itu terjadi untuk kasus di mana kolom target tidak disebutkan dalam indeks tidak berkerumun:

Faktanya, dalam dua kasus pertama, halaman baru dialokasikan (Anda dapat memvalidasinya dengan DBCC IND , seperti yang dilakukan Spörri dalam jawabannya), sehingga operasi dapat terjadi secara online, tetapi itu tidak berarti cepat (karena masih harus menulis salinan semua data itu, dan membuat NULL bitmap berubah sebagai bagian dari menulis setiap halaman baru, dan mencatat semua aktivitas itu).

Saya pikir kebanyakan orang akan curiga bahwa mengubah kolom dari NOT NULL ke NULL hanya metadata di semua skenario, tetapi saya telah menunjukkan di sini bahwa ini tidak benar jika kolom direferensikan oleh indeks non-cluster (dan hal serupa terjadi apakah itu kunci atau INCLUDE kolom). Mungkin operasi ini juga bisa dipaksa menjadi ONLINE di Azure SQL Database hari ini, atau mungkinkah di versi utama berikutnya? Ini tidak serta merta membuat operasi fisik yang sebenarnya terjadi lebih cepat, tetapi akibatnya akan mencegah pemblokiran.

Saya tidak menguji skenario itu (dan analisis apakah itu benar-benar online lebih sulit di Azure), saya juga tidak mengujinya di tumpukan. Sesuatu yang dapat saya kunjungi kembali di posting mendatang. Sementara itu, berhati-hatilah dengan asumsi apa pun yang mungkin Anda buat tentang operasi metadata saja.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Instal dan Konfigurasi Perangkat Lunak XAMPP di Windows Server 2019

  2. Inisialisasi File Instan:Dampak Selama Penyiapan

  3. RDBMS vs NoSQL

  4. Cara Menghitung Nilai Absolut dalam SQL

  5. Kurangi panggilan basis data untuk meningkatkan kinerja situs web