Tidak yakin apakah itu bug, per se tapi itu jelas suatu kejadian yang menarik. Rekondisi partisi online baru di SQL Server 2014 sehingga mungkin ada beberapa internal untuk menyortir dengan ini.
Inilah penjelasan terbaik saya untuk Anda. Statistik tambahan benar-benar mengharuskan semua partisi disampel pada tingkat yang sama sehingga ketika mesin menggabungkan halaman statistik, dapat yakin bahwa distribusi sampel dapat dibandingkan. REBUILD
tentu sampel data pada tingkat sampel 100%. Tidak ada jaminan bahwa laju sampel 100% pada partisi 9 akan selalu menjadi laju sampel yang tepat dari sisa partisi. Karena ini, sepertinya mesin tidak dapat menggabungkan sampel dan Anda berakhir dengan gumpalan statistik kosong. Namun, objek statistik masih ada:
select
check_time = sysdatetime(),
schema_name = sh.name,
table_name = t.name,
stat_name = s.name,
index_name = i.name,
stats_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
s.stats_id,
s.has_filter,
s.is_incremental,
s.auto_created,
sp.last_updated,
sp.rows,
sp.rows_sampled,
sp.unfiltered_rows,
modification_counter
from sys.stats s
join sys.tables t
on s.object_id = t.object_id
join sys.schemas sh
on t.schema_id = sh.schema_id
left join sys.indexes i
on s.object_id = i.object_id
and s.name = i.name
outer apply sys.dm_db_stats_properties(s.object_id, s.stats_id) sp
where t.name = 'TransactionHistory' and sh.name = 'dbo'
Anda dapat mengisi gumpalan melalui sejumlah cara:
UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE;
atau
UPDATE STATISTICS dbo.TransactionHistory (IDX_ProductId) WITH RESAMPLE ON PARTITIONS (9);
atau Anda bisa menunggu AutoStats untuk memperbarui pada kompilasi pertama dari rencana permintaan menggunakan objek itu:
-- look at my creative query
select *
from dbo.TransactionHistory
where TransactionDate = '20140101';
Setelah mengatakan semua itu, pos yang mencerahkan ini oleh Erin Stellato menyoroti apa yang kemudian dianggap sebagai kekurangan utama dari statistik tambahan. Data tingkat partisi mereka tidak digunakan oleh pengoptimal dalam pembuatan paket kueri, mengurangi manfaat statistik tambahan yang diperkirakan. Lalu, apa manfaat statistik inkremental saat ini? Saya akan menyampaikan bahwa utilitas utama mereka adalah dalam kemampuan untuk sampel tabel besar lebih konsisten pada tingkat yang lebih tinggi daripada dengan statistik tradisional.
Menggunakan contoh Anda, beginilah tampilannya:
set statistics time on;
update statistics dbo.TransactionHistory(IDX_ProductId)
with fullscan;
--SQL Server Execution Times:
-- CPU time = 94 ms, elapsed time = 131 ms.
update statistics dbo.TransactionHistory(IDX_ProductId)
with resample on partitions(2);
--SQL Server Execution Times:
-- CPU time = 0 ms, elapsed time = 5 ms.
drop index IDX_ProductId On dbo.TransactionHistory;
CREATE NONCLUSTERED INDEX IDX_ProductId ON dbo.TransactionHistory (ProductId)
WITH (DATA_COMPRESSION = ROW)
ON [PRIMARY]
update statistics dbo.TransactionHistory(IDX_ProductId)
with fullscan;
--SQL Server Execution Times:
-- CPU time = 76 ms, elapsed time = 66 ms.
Pembaruan statistik fullscan pada tambahan biaya statistik 131 ms. Pembaruan statistik fullscan pada statistik non-partisi-aligned 66 ms. Statistik yang tidak selaras lebih lambat kemungkinan besar karena biaya overhead yang dikeluarkan dengan menggabungkan halaman statistik individu kembali ke histogram utama. Namun, menggunakan objek statistik partisi-sejajar, kita dapat memperbarui satu partisi dan menggabungkannya kembali ke gumpalan histogram utama dalam 5 ms. Jadi pada titik ini administrator dengan statistik tambahan dihadapkan dengan keputusan. Mereka dapat mengurangi waktu pemeliharaan statistik keseluruhan dengan hanya memperbarui partisi yang secara tradisional perlu diperbarui, atau mereka dapat bereksperimen dengan laju sampel yang lebih tinggi sehingga mereka berpotensi mendapatkan lebih banyak sampel baris dalam periode waktu yang sama dengan jangka waktu pemeliharaan sebelumnya. Yang pertama memungkinkan ruang bernapas di jendela pemeliharaan, yang terakhir mungkin mendorong statistik di meja yang sangat besar ke tempat di mana pertanyaan mendapatkan rencana yang lebih baik berdasarkan statistik yang lebih akurat. Ini bukan jaminan dan jarak tempuh Anda mungkin beragam.
Pembaca dapat melihat bahwa 66 ms bukan waktu pembaruan statistik yang menyakitkan pada tabel ini, jadi saya mencoba menyiapkan tes pada set data stackexchange. Ada 6.418.608 posting (tidak termasuk posting StackOverflow dan semua posting dari 2012 - kesalahan data di pihak saya) di dump terbaru yang saya unduh.
Saya telah mempartisi data oleh [CreationDate]
karena ... demo.
Berikut adalah beberapa pengaturan waktu untuk beberapa skenario standar yang cantik (100% - pembangunan kembali indeks, default - statistik pembaruan otomatis atau UPDATE STATISTICS
tanpa laju sampel yang ditentukan:
- Buat Statistik Non-Incremental dengan Fullscan: Waktu CPU = 23500 ms, waktu yang berlalu = 22521 ms.
- Buat Statistik Incremental Dengan Fullscan: Waktu CPU = 20406 ms, waktu yang berlalu = 15413 ms.
- Perbarui Statistik Non-Tambahan dengan Tingkat Sampel Default: Waktu CPU = 406 ms, waktu yang berlalu = 408 ms.
- Perbarui Statistik Tambahan dengan Tingkat Sampel Default: Waktu CPU = 453 ms, waktu yang berlalu = 507 ms.
Katakanlah kita lebih canggih dari skenario default ini dan telah memutuskan bahwa tingkat sampel 10% adalah tingkat minimum yang seharusnya memberi kita rencana yang kita butuhkan sambil menjaga waktu pemeliharaan ke jangka waktu yang masuk akal.
- Perbarui Statistik Non-Incremental dengan sampel 10 persen: Waktu CPU = 2344 ms, waktu yang berlalu = 2441 ms.
- Perbarui Statistik Tambahan dengan sampel 10 persen: Waktu CPU = 2344 ms, waktu yang berlalu = 2388 ms.
Sejauh ini tidak ada manfaat yang jelas untuk memiliki statistik tambahan. Namun, jika kami memanfaatkan DMV yang tidak berdokumen sys.dm_db_stats_properties_internal()
(di bawah), Anda bisa mendapatkan wawasan tentang partisi mana yang ingin Anda perbarui. Katakanlah kami membuat perubahan pada data di partisi 3 dan kami ingin memastikan statistik baru untuk kueri yang masuk. Berikut ini pilihan kami:
- Perbarui Non-Incremental di Default (juga perilaku default dari Pembaruan Statistik Otomatis): 408 ms.
- Perbarui Non-inkremental pada 10%: 2441 ms.
- Perbarui Statistik Tambahan, Partisi 3 Dengan Sampel Ulang (10% - laju sampel yang ditentukan kami): Waktu CPU = 63 ms, waktu yang berlalu = 63 ms.
Di sinilah kita perlu mengambil keputusan. Apakah kita mengambil kemenangan 63 ms. pembaruan statistik berbasis partisi, atau apakah kita meningkatkan laju sampel lebih tinggi? Katakanlah kita bersedia untuk mengambil hit sampel awal sebesar 50% pada statistik tambahan:
- Perbarui Statistik Tambahan pada 50%: waktu yang berlalu = 16840 ms.
- Perbarui Statistik Tambahan, Partisi 3 dengan Resample (50% - waktu pembaruan baru kami): waktu yang berlalu = 295 ms.
Kami dapat mengambil sampel lebih banyak data, mungkin menyiapkan pengoptimal untuk membuat perkiraan yang lebih baik tentang data kami (meskipun belum menggunakan statistik tingkat partisi) dan kami dapat melakukan ini lebih cepat sekarang karena kami memiliki statistik tambahan.
Namun, satu hal yang menyenangkan untuk dipecahkan. Bagaimana dengan pembaruan statistik sinkron? Apakah tingkat sampel 50% dipertahankan bahkan ketika autostats masuk?
Saya menghapus data dari partisi 3 dan menjalankan kueri pada CreationDate dan memeriksa kemudian memeriksa tarif dengan kueri yang sama di bawah ini. Tingkat sampel 50% dipertahankan.
Jadi, cerita panjang pendek: Statistik tambahan dapat menjadi alat yang berguna dengan jumlah pemikiran yang tepat dan pekerjaan pengaturan awal. Namun, Anda harus tahu masalah yang Anda coba selesaikan dan kemudian Anda harus menyelesaikannya dengan tepat. Jika Anda mendapatkan perkiraan kardinalitas yang buruk, Anda mungkin bisa mendapatkan rencana yang lebih baik dengan laju sampel strategis dan beberapa intervensi yang diinvestasikan. Namun, Anda hanya mendapatkan sebagian kecil dari manfaatnya karena histogram yang digunakan adalah halaman statistik tunggal yang digabungkan dan bukan informasi tingkat partisi. Jika Anda merasa sakit di jendela pemeliharaan, maka mungkin statistik tambahan dapat membantu Anda, tetapi mungkin akan mengharuskan Anda menyiapkan proses intervensi pemeliharaan sentuhan tinggi. Bagaimanapun,:
- Statistik dibuat dengan indeks yang tidak disejajarkan dengan tabel dasar.
- Statistik dibuat pada database sekunder AlwaysOn yang dapat dibaca.
- Statistik dibuat pada basis data baca-saja.
- Statistik dibuat pada indeks yang difilter.
- Statistik dibuat pada tampilan.
- Statistik dibuat di tabel internal.
- Statistik dibuat dengan indeks spasial atau indeks XML.
Semoga ini membantu
select
sysdatetime(),
schema_name = sh.name,
table_name = t.name,
stat_name = s.name,
index_name = i.name,
leading_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
s.stats_id,
parition_number = isnull(sp.partition_number,1),
s.has_filter,
s.is_incremental,
s.auto_created,
sp.last_updated,
sp.rows,
sp.rows_sampled,
sp.unfiltered_rows,
modification_counter = coalesce(sp.modification_counter, n1.modification_counter)
from sys.stats s
join sys.tables t
on s.object_id = t.object_id
join sys.schemas sh
on t.schema_id = sh.schema_id
left join sys.indexes i
on s.object_id = i.object_id
and s.name = i.name
cross apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) sp
outer apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) n1
where n1.node_id = 1
and (
(is_incremental = 0)
or
(is_incremental = 1 and sp.partition_number is not null)
)
and t.name = 'Posts'
and s.name like 'st_posts%'
order by s.stats_id,isnull(sp.partition_number,1)