Ascending Key Problem - Memimpin kolom bermerek "Stationary" - SQL Server

9

Saya telah meneliti permintaan yang berjalan lambat di database kami, dan telah menyimpulkan bahwa ini adalah Masalah Kunci Ascending klasik. Karena baris baru disisipkan hampir secara konstan, dan sepotong SQL yang diberikan untuk menarik data terbaru dari DB berjalan setiap 30 menit, opsi pertama untuk memperbarui statistik setiap 30 menit terdengar seperti itu bisa menjadi pemborosan sumber daya.

Jadi, saya melihat ke Trace Flag 2389 yang pada prinsipnya harus membantu, namun itu membutuhkan kolom Leading untuk dicap sebagai Ascending, dan ketika saya menggunakan Trace Flag 2388 untuk memeriksa statistik indeks (PK), saya melihat bahwa kolom terkemuka sebenarnya dicap sebagai Stationary - karena untuk beberapa indeks PK pada tabel lain diperbarui pada saat yang sama.

masukkan deskripsi gambar di sini

Tampaknya tidak ada banyak panduan tentang apa yang menghasilkan branding Stationary, namun saya menemukan KB2952101 yang mengatakan jika kurang dari 90% insert lebih besar dari nilai maksimum yang lama, itu akan digolongkan sebagai Stationary. Semua sisipan kami adalah kiriman baru, dan kolom utama adalah kolom IDENTITAS bigint, jadi 100% sisipan harus lebih besar dari nilai maksimum sebelumnya.

Jadi pertanyaan saya adalah mengapa kolom akan dicap sebagai Stationary, padahal itu jelas Ascending?

Upaya sebelumnya untuk menyelesaikan masalah ini untuk beberapa harian yang menjalankan SQL (yang bekerja dengan sangat baik) menghasilkan pekerjaan yang diatur untuk memperbarui statistik untuk tabel ini setiap malam. Pembaruan tidak melakukan FULLSCAN, jadi mungkinkah pemindaian sampel terkadang melewatkan baris baru, sehingga tidak selalu muncul sebagai naik?

Satu-satunya hal lain yang dapat saya pikirkan yang dapat mempengaruhi hal ini, adalah bahwa kami memiliki pekerjaan arsip yang berjalan di belakang layar menghapus baris pada usia tertentu. Mungkinkah ini berdampak pada branding?

Servernya adalah SQL Server 2012 SP1.

Pembaruan : Lain hari, pembaruan statistik lainnya - pencitraan stasioner yang sama. Ada 28049 sisipan baru sejak pembaruan statistik sebelumnya. Setiap baris memiliki stempel waktu ketika dimasukkan, jadi jika saya memilih maks (id) dari tabel di mana stempel waktu <'20161102' Saya mendapatkan 23313455 Demikian pula, jika saya melakukan itu ketika statistik diperbarui hari ini, saya mendapatkan 23341504.

Perbedaan antara ini adalah 28049 sisipan baru, jadi seperti yang Anda lihat, semua sisipan baru diberi kunci naik baru (seperti yang diharapkan), menyarankan kolom terkemuka harus dicap sebagai naik bukan stasioner.

Selama periode yang sama, pekerjaan pengarsipan kami menghapus 213.629 baris (kami perlahan membersihkan data lama). Apakah ada kemungkinan bahwa pengurangan jumlah baris dapat berkontribusi pada pencitraan stasioner? Saya sudah menguji ini sebelumnya dan sepertinya tidak ada bedanya.

Pembaruan 2 : Satu hari lagi, pembaruan statistik lainnya, dan kolom sekarang ditandai sebagai Naik! Sesuai teori tentang penghapusan yang mempengaruhi hal ini, saya memeriksa persentase pembaruan yang disisipkan dibandingkan dengan yang dihapus, dan kemarin 13% adalah sisipan, sedangkan sisipan dua hari sebelumnya menyumbang sekitar 12%. Saya tidak berpikir itu memberi kita sesuatu yang konklusif.

Menariknya, tabel terkait yang mendapatkan rata-rata 4 baris yang dimasukkan untuk setiap baris dimasukkan ke dalam tabel utama ini, dan apakah statistiknya diperbarui pada saat yang sama, apakah kolom IDENTITAS PK-nya masih stasioner !?

Pembaruan 3 : Selama akhir pekan kami mendapatkan lebih banyak sisipan. Pagi ini kolom utama kembali ke Alat Tulis. Pada pembaruan statistik terakhir, kami memiliki 46840 sisipan dan hanya 34.776 yang dihapus.

Sekali lagi, yang menarik, tabel terkait yang saya sebutkan di atas sekarang memiliki kolom terkemuka bermerek Ascending. Apakah tidak ada dokumentasi yang dapat menjelaskan hal ini?

Pembaruan 4 : Sudah seminggu atau lebih sekarang, pekerjaan pengarsipan telah menghapus simpanan, jadi kami secara konsisten menghapus sekitar dua pertiga dari jumlah baris yang dimasukkan. Statistik menunjukkan hasil beragam di tabel terkait, dengan satu menunjukkan stasioner, dan dua menunjukkan naik, meskipun mereka semua diperbarui secara proporsional dengan cara yang sama.

Nik
sumber
Dalam kasus kami, semua sisipan memiliki nilai yang melampaui nilai tertinggi dalam histogram, jadi kolom tidak boleh bermerek Stasioner, jadi saya belum mencoba benderanya. Ini adalah penjelasan mengapa SQL Server tampaknya secara acak merek kolom yang saya benar-benar setelah. Terima kasih.
Nik

Jawaban:

3

Tampaknya tidak ada banyak panduan tentang apa yang menghasilkan branding Stasioner, namun saya menemukan KB2952101 yang mengatakan jika kurang dari 90% sisipan lebih besar dari nilai maksimum yang lama, itu akan digolongkan Stasioner. Semua sisipan kami adalah kiriman baru, dan kolom utama adalah kolom IDENTITAS bigint, jadi 100% sisipan harus lebih besar dari nilai maksimum sebelumnya.

Jadi pertanyaan saya adalah mengapa kolom akan dicap sebagai Stationary, padahal itu jelas Ascending?

Itu akan bermerek stasioner jika, seperti yang telah Anda sebutkan, bahwa 10% atau lebih dari sisipan tidak naik. Jika 100% dari sisipan Anda seperti yang Anda katakan ... maka Anda mungkin tidak memiliki masalah ini, sampai tentu saja Anda menghapus tetapi kemudian akan kembali ke yang tidak diketahui.

Ini adalah repro masalah Anda:

use master;
go
-- create a database for this to test
create database AscendingKey;
go

use AscendingKey;
go
-- create a test table
create table dbo.AscendingKeyTableTest
(
    SomeData        char(100) default('A'),
    AscendingKey    bigint not null,
);
go

-- insert some dummy data
set nocount on
go

declare @i int = 1

while(@i <= 1000)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- create stats on the ascendingkey column
create statistics AscendingKeyStats on dbo.AscendingKeyTableTest(AscendingKey);
go

-- look at the stats
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- ascending!
-- we hit the 3x stats updates to have it 'learn'

-- what happens if we insert more than 10% that isn't ascending
declare @i int = 1;

while(@i <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- still says ascending... but...
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- what if we update again?
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go
-- stationary
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- get it back to ascending
declare @i int;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+1);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+2);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+3);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go

-- what about the deletes?
delete from AscendingKeyTableTest where AscendingKey % 3 = 0
go

update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- back to unknown

-- cleanup
use master
go

drop database AscendingKey
go
Sean Gallardy - Pensiunan Pengguna
sumber
Saya melakukan tes cepat menggunakan skrip yang sama seperti di atas tetapi hanya menjalankan memasukkan dan menghapus bagian. Tampaknya jika Anda menghapus jumlah baris yang jauh lebih besar daripada yang disisipkan, ia akan kembali ke stasioner (lagi sekitar 10%). Dalam data Anda yang diperbarui, Anda telah menyisipkan sekitar 10% dari semua perubahan data yang dilakukan - tampaknya penghapusan memberi Anda kesedihan. Pada titik ini saya akan menyarankan membiarkan objek statistik menekan naik dan kemudian membekukannya dengan tidak memperbaruinya.
Sean Gallardy - Pensiunan Pengguna
Saya mencoba menciptakan kembali apa yang telah Anda lakukan, dan akhirnya menambahkan 10 baris lagi dan menghapus 1000, memperbarui statistik, lalu menampilkan statistik, dan masih muncul sebagai naik: Sisipan sejak pembaruan terakhir: 10, Menghapus sejak pembaruan terakhir: 1000, jenis kolom Terkemuka : Naik. Tidak yakin mengapa saya mendapatkan hasil berbeda untuk Anda? Jika temuan Anda benar, Mungkin hanya kasus memasang dengan hasil yang kurang optimal sekarang, maka ketika tumpukan arsip kami telah dihapus, coba lagi.
Nik
0

Menurut perkiraan saya, kecuali jika Anda membuat kolom kunci utama di server itu sendiri, Anda bisa masuk ke lubang kecil dengan mengandalkan itu yang dihasilkan pada masing-masing klien.

Anda juga sudah mencoba Trace Flag 2371.

TF 2371 didokumentasikan di sini .

KB berjudul "Controlling Autostat (AUTO_UPDATE_STATISTICS) perilaku dalam SQL Server." dan KB adalah 2754171.

Ini akan sangat berguna jika Anda membuat daftar untuk kami dampak aktual dari data baru yang tidak masuk ke dalam statistik tepat waktu.

Indeks yang salah dipilih. Dan, jika demikian bisakah Anda membuat daftar untuk kami indeks dan kunci utamanya?

Juga, bisakah Anda membagikan rencana yang dihasilkan ketika statistik tanggal terhadap ketika mereka tepat waktu. Saya ingin membandingkan keduanya.

Pemikiran saya adalah bahwa keputusan Pengoptimal Berbasis Biaya (Aturan dan Penetapan Biaya) SQL cukup bagus; di luar area esoteris seperti ini.

Jika ini adalah kasus khusus, penjelasan lebih lanjut mungkin dapat membantu dan membenarkan membuka Item Hubungkan.

Selain itu, menurut pendapat saya, Anda akan memiliki manfaat keseluruhan yang lebih besar dalam membuat vendor menggunakan SP daripada ad-hoc SQL.

Daniel Adeniji
sumber
Terima kasih, semua ID dibuat oleh SQL Server. Saya mengerti flag 2371 hanya membuat pembaruan statistik lebih sering. Dilihat oleh tabel di brentozar.com/archive/2016/03/... , ukuran tabel kami (14M baris), dan jumlah sisipan harian (28K baris), statistik akan tetap hanya diperbarui setiap 4 hari atau lebih, jadi ekstrak data baru sebagian besar waktu tidak akan mengetahui data baru. Kueri yang saya lihat bukan masalah, itu memahami bagaimana SQL Server memberi merek kolom terkemuka yang ingin saya ketahui. Terima kasih lagi.
Nik