Di Dynamics AX ada mekanisme caching di mana tabel dapat dikonfigurasi untuk dimuat ke dalam memori dan di-cache. Cache ini terbatas pada jumlah tertentu dari KB untuk mencegah masalah memori. Pengaturan yang saya bicarakan dipanggil entiretablecache
dan memuat seluruh tabel dalam memori segera setelah satu catatan diminta.
Hingga baru-baru ini kami mengandalkan beberapa skrip untuk memverifikasi ukuran tabel yang memiliki pengaturan ini untuk melihat apakah ukuran tabel di atas batas ini.
Namun sekarang, kompresi ikut berperan dan hal-hal seperti sp_spaceused atau sys.allocation_units tampaknya melaporkan ruang yang sebenarnya digunakan oleh data terkompresi.
Jelas, server aplikasi bekerja dengan data yang tidak terkompresi sehingga ukuran data pada disk di SQL Server tidak relevan. Saya membutuhkan ukuran sebenarnya dari data yang tidak terkompresi.
Saya tahu sp_estimate_data_compression_savings tetapi seperti namanya, ini hanya perkiraan.
Saya lebih suka memiliki ukuran yang setepat mungkin.
Satu-satunya cara saya bisa memikirkan adalah beberapa SQL dinamis yang berbelit-belit membuat tabel terkompresi dengan struktur yang sama dengan tabel terkompresi, memasukkan data terkompresi dalam tabel bayangan itu dan kemudian memeriksa ukuran tabel bayangan itu.
Tak perlu dikatakan, ini agak membosankan dan perlu beberapa saat untuk berjalan pada database beberapa ratus GB.
Powershell bisa menjadi pilihan, tapi saya tidak ingin mengulangi semua tabel untuk melakukan select *
pada mereka untuk memeriksa ukuran dalam skrip karena itu hanya akan membanjiri cache dan mungkin akan memakan waktu lama juga.
Singkatnya, saya butuh cara untuk mendapatkan ukuran untuk setiap tabel karena akan pernah terkompresi dan dengan fragmentasi keluar dari persamaan seperti yang disajikan ke aplikasi, jika itu mungkin. Saya terbuka untuk pendekatan yang berbeda, T-SQL lebih disukai tetapi saya tidak menentang Powershell atau pendekatan kreatif lainnya.
Asumsikan buffer dalam aplikasi adalah ukuran data. Bigint selalu berukuran bigint, dan tipe data karakter adalah 2 byte per karakter (unicode). Data BLOB mengambil ukuran data juga, enum pada dasarnya adalah int dan data numerik adalah numerik (38,12), datetime adalah ukuran datetime. Juga, tidak ada NULL
nilai, mereka disimpan sebagai string kosong, 1900-01-01
atau nol.
Tidak ada dokumentasi tentang bagaimana ini diterapkan, tetapi asumsi didasarkan pada beberapa pengujian dan skrip yang digunakan oleh PFE dan tim dukungan (yang juga mengabaikan kompresi tampaknya, karena cek dibangun dalam aplikasi dan aplikasi tidak dapat memberitahu jika data yang mendasarinya dikompresi) yang juga memeriksa ukuran tabel. Tautan ini misalnya menyatakan:
Hindari menggunakan cache Seluruh Tabel untuk tabel besar (di AX 2009 lebih dari 128 KB atau 16 halaman, di AX 2012 atas pengaturan aplikasi 'seluruh tabel ukuran cache' [default: 32KB, atau 4 halaman]) - alih-alih pindah ke caching rekaman.
sumber
Jawaban:
Sementara keinginan untuk informasi ini tentu dapat dimengerti, mendapatkan informasi ini, terutama dalam konteks "koreksi mungkin" lebih sulit daripada yang diharapkan semua orang karena asumsi yang salah. Apakah melakukan ide tabel bayangan terkompresi yang disebutkan dalam pertanyaan, atau saran @ sp_BlitzErik dalam komentar tentang mengembalikan DB dan membuka kompresi di sana untuk memeriksa, tidak boleh diasumsikan bahwa ukuran tabel terkompresi == ukuran data kata dalam memori di server aplikasi:
Apakah semua baris dalam tabel di-cache? Atau hanya dalam jangkauan? Asumsinya di sini adalah itu semua, dan itu mungkin benar, tetapi saya pikir setidaknya harus disebutkan bahwa ini mungkin tidak terjadi (kecuali dokumentasi menyatakan sebaliknya, tapi ini adalah poin kecil, hanya saja tidak mau itu tidak disebutkan).
Pertanyaan telah diperbarui untuk menyatakan: ya, semua baris sedang di-cache.
Struktur di atas kepala
Halaman dan overhead-baris di sisi DB: Berapa banyak baris yang cocok pada halaman ditentukan oleh banyak faktor yang dapat membuang perkiraan. Bahkan dengan nilai
FILLFACTOR
100 (atau 0), masih ada kemungkinan ada ruang yang tidak digunakan yang tersisa pada halaman karena tidak cukup untuk seluruh baris. Dan itu selain tajuk halaman. Juga, jika fungsi Snapshot Isolasi diaktifkan, saya yakin akan ada tambahan 13 byte per baris yang diambil oleh nomor versi, dan itu akan membuang perkiraan. Ada hal-hal kecil lainnya yang terkait dengan ukuran aktual baris (bitmap NULL, kolom panjang variabel, dll) tetapi item yang disebutkan sejauh ini seharusnya hanya menjadi titik.Jenis koleksi apa yang digunakan untuk menyimpan hasil yang di-cache? Saya menganggap ini adalah aplikasi .NET, jadi apakah itu
DataTable
? Daftar generik? A SortedDictionary? Setiap jenis koleksi memiliki jumlah pendengaran yang berbeda. Saya tidak akan mengharapkan salah satu opsi untuk selalu mencerminkan overhead Page dan Row di sisi DB, terutama pada skala (saya yakin sejumlah kecil baris mungkin tidak memiliki cukup beragam masalah, tetapi Anda tidak mencari perbedaan dalam ratusan byte atau hanya beberapa kB).CHAR
/VARCHAR
data disimpan pada 1 byte per karakter (mengabaikan karakter byte ganda untuk saat ini).XML
dioptimalkan agar tidak memakan ruang hampir seperti yang ditunjukkan oleh representasi teks. Datatype ini membuat kamus elemen dan nama atribut dan menggantikan referensi yang sebenarnya untuk mereka dalam dokumen dengan ID masing-masing (agak bagus, sebenarnya). Jika tidak, semua nilai string adalah UTF-16 (2 atau 4 byte per "karakter"), sepertiNCHAR
/NVARCHAR
.DATETIME2
adalah antara 6 dan 8 byte.DECIMAL
adalah antara 5 dan 17 byte (tergantung pada presisi).Strings (sekali lagi, dengan asumsi .NET) selalu UTF-16. Tidak ada optimasi untuk string 8-bit seperti yang
VARCHAR
berlaku. TETAPI, string juga bisa "diinternir" yang merupakan salinan bersama yang dapat direferensikan berkali-kali (tapi saya tidak tahu apakah ini berfungsi untuk string dalam koleksi, atau jika demikian, apakah itu berfungsi untuk semua jenis koleksi).XML
mungkin atau mungkin tidak disimpan dengan cara yang sama dalam memori (saya harus mencari tahu itu).DateTime
selalu 8 byte (seperti T-SQLDATETIME
, tapi tidak sepertiDATE
,TIME
, atauDATETIME2
).Decimal
adalah selalu 16 byte .Semua itu untuk mengatakan: hampir tidak ada yang dapat Anda lakukan di sisi DB untuk mendapatkan ukuran jejak memori yang bahkan cukup akurat di sisi server aplikasi. Anda perlu menemukan cara untuk menginterogasi server aplikasi itu sendiri, setelah dimuat dengan tabel tertentu, jadi tahu seberapa besar itu. Dan saya tidak yakin apakah debugger akan membiarkan Anda melihat ukuran runtime dari koleksi yang diisi. Jika tidak, maka satu-satunya cara untuk mendekati adalah melalui semua baris tabel, mengalikan setiap kolom dengan ukuran .NET yang sesuai (misalnya
INT
=* 4
,VARCHAR
=DATALENGTH() * 2
,NVARCHAR
=DATALENGTH()
,XML
= 🙃, dll), tetapi itu masih menyisakan pertanyaan. dari overhead koleksi ditambah setiap elemen koleksi.Diberi beberapa definisi baru dalam pertanyaan, orang mungkin bisa melakukan kueri berikut untuk mendapatkan lebih dekat. Dan tidak masalah apakah tabel dikompresi atau tidak, meskipun terserah masing-masing orang untuk menentukan apakah pemindaian semua baris sesuai pada Produksi (mungkin dilakukan dari pemulihan atau selama jam sibuk):
Tapi ingat, ini tidak termasuk pengumpulan atau pengumpulan elemen koleksi. Dan tidak yakin apakah kita bisa mendapatkan nilai itu tanpa debugger (atau mungkin sesuatu seperti ILSpy, tapi saya tidak merekomendasikan hal itu karena mungkin melanggar EULA tergantung pada undang-undang setempat).
sumber
Dari pertanyaan Anda, sepertinya Anda memiliki ukuran cache maksimum
S
dan Anda tidak ingin memuat tabel ke dalam cache yang melebihi ukuran itu. Jika itu benar maka Anda tidak perlu tahu ukuran pasti dari setiap tabel. Anda hanya perlu tahu apakah tabel lebih besar atau lebih kecil dari ukuran cache maksimumS
. Itu adalah masalah yang jauh lebih mudah tergantung pada definisi kolom dan jumlah baris tabel Anda.Saya setuju dengan jawaban luar biasa Solomon Rutzky dalam melihat data yang tidak terkompresi bukanlah cara yang tepat dan mungkin sulit untuk menghasilkan perkiraan yang baik untuk ukuran sebenarnya dari tabel dalam cache. Namun, saya akan bekerja dalam kerangka pertanyaan dan menganggap bahwa Anda dapat mengembangkan rumus yang cukup dekat berdasarkan definisi kolom untuk tipe data statis dan panjang aktual kolom dinamis Anda.
Jika Anda memiliki pemetaan tipe data ke ukuran cache maka Anda harus dapat mengevaluasi beberapa tabel tanpa melihat data di dalamnya:
sys.partitions
dan menghitung ukuran tabel menggunakan definisi kolom.BIGINT
kolom dapat memiliki ukuran data yang berukuran 10000000 * (8 + 8 + 8 + 8 + 8) = 400 M byte yang bisa lebih besar dari batas ukuran cache AndaS
. Tidak masalah jika memiliki banyak kolom string juga.BIGINT
kolom danNVARCHAR(20)
kolom mungkin tidak melebihi 100 * (8 + 2 * 20) = 4800 byte.S
itu sangat tidak mungkin masuk dalam cache. Anda harus melakukan pengujian untuk mengetahui apakah nilai tersebut ada.Anda mungkin harus meminta data tabel yang tidak sesuai dengan kriteria di atas. Ada beberapa trik yang bisa Anda gunakan untuk meminimalkan dampak kinerja ini. Saya akan mengatakan bahwa Anda memiliki dua prioritas yang bersaing di sini: Anda menghargai keakuratan tetapi juga tidak ingin memindai semua data dalam database Anda. Dimungkinkan untuk menambahkan semacam buffer ke dalam perhitungan Anda. Saya tidak tahu apakah itu lebih dapat diterima untuk mengecualikan tabel yang sedikit di bawah ukuran cache maksimum
S
atau untuk memasukkan tabel yang sedikit di atas ukuran cache maksimum.Berikut adalah beberapa ide untuk membuat kueri yang melihat data tabel lebih cepat:
TABLESAMPLE
selama ukuran sampel Anda cukup besar.SUM()
yang berhenti lebih awal berdasarkan nilai agregat itu. Saya hanya pernah melihat itu berhasilROW_NUMBER()
. Tapi Anda bisa memindai 10% pertama dari tabel, menghemat ukuran data yang dihitung, memindai 10% berikutnya, dan seterusnya. Untuk tabel yang terlalu besar untuk cache, Anda mungkin dapat menyimpan sejumlah besar pekerjaan dengan pendekatan ini dengan berhenti lebih awal.Saya menyadari bahwa saya tidak memasukkan kode SQL dalam jawaban ini. Beri tahu saya jika akan membantu untuk menulis kode demo untuk semua ide yang saya diskusikan di sini.
sumber