Meskipun saya tidak setuju bahwa BLOB seharusnya ada di tabel lain - mereka tidak boleh ada di database sama sekali . Menyimpan pointer ke tempat file tinggal di disk, dan kemudian dapatkan dari database ...
Masalah utama yang mereka sebabkan (bagi saya) adalah pengindeksan. Menggunakan XML dengan paket kueri, karena semua orang mengerti, mari kita buat tabel:
SELECT TOP 1000
ID = IDENTITY(INT,1,1),
deq.query_plan
INTO dbo.index_test
FROM sys.dm_exec_cached_plans AS dec
CROSS APPLY sys.dm_exec_query_plan(dec.plan_handle) AS deq
ALTER TABLE dbo.index_test ADD CONSTRAINT pk_id PRIMARY KEY CLUSTERED (ID)
Ini hanya 1000 baris, tetapi memeriksa ukuran ...
sp_BlitzIndex @DatabaseName = 'StackOverflow', @SchemaName = 'dbo', @TableName = 'index_test'
Ini lebih dari 40 MB hanya untuk 1000 baris. Dengan asumsi Anda menambahkan 40 MB setiap 1000 baris, itu bisa menjadi sangat jelek dengan cepat. Apa yang terjadi ketika Anda menekan 1 juta baris? Itu hanya sekitar 1 TB data, di sana.
Setiap pertanyaan yang perlu menggunakan indeks berkerumun Anda sekarang harus membaca semua data BLOB itu menjadi klarifikasi memori : ketika kolom data BLOB direferensikan.
Bisakah Anda memikirkan cara yang lebih baik untuk menggunakan memori SQL Server daripada menyimpan BLOB? Karena saya yakin bisa.
Memperluasnya ke indeks nonclustered:
CREATE INDEX ix_noblob ON dbo.index_test (ID)
CREATE INDEX ix_returnoftheblob ON dbo.index_test (ID) INCLUDE (query_plan)
Anda dapat mendesain indeks nonclustered Anda untuk sebagian besar menghindari kolom BLOB sehingga permintaan reguler dapat menghindari indeks clustered, tetapi segera setelah Anda membutuhkan kolom BLOB itu, Anda memerlukan indeks clustered.
Jika Anda menambahkannya sebagai INCLUDED
kolom pada indeks yang tidak dikelompokkan untuk menghindari skenario pencarian kunci, Anda akan berakhir dengan indeks raksasa yang tidak tercakup:
Lebih banyak masalah yang mereka sebabkan:
- Jika ada yang menjalankan
SELECT *
kueri, mereka mendapatkan semua data BLOB itu.
- Mereka mengambil ruang dalam cadangan dan memulihkan, memperlambatnya
- Mereka melambat
DBCC CHECKDB
, karena saya tahu Anda sedang memeriksa korupsi, kan?
- Dan jika Anda melakukan pemeliharaan indeks, mereka memperlambatnya juga.
Semoga ini membantu!
Seberapa besar gambar-gambar ini, dan berapa banyak yang Anda harapkan? Sementara saya sebagian besar setuju dengan @sp_BlitzErik , saya pikir ada beberapa skenario di mana itu ok untuk melakukan ini, dan itu akan membantu untuk memiliki gambaran yang lebih jelas tentang apa yang sebenarnya diminta di sini.
Beberapa opsi untuk dipertimbangkan yang mengurangi sebagian besar aspek negatif yang ditunjukkan oleh Erik adalah:
Kedua opsi ini dirancang sebagai jalan tengah antara menyimpan BLOB sepenuhnya di SQL Server atau sepenuhnya di luar (kecuali untuk string colun untuk mempertahankan jalur). Mereka memungkinkan BLOB untuk menjadi bagian dari model data dan berpartisipasi dalam Transaksi sambil tidak membuang-buang ruang dalam buffer pool (yaitu memori). Data BLOB masih termasuk dalam cadangan, yang membuatnya mengambil lebih banyak ruang dan lebih lama untuk mencadangkan danuntuk mengembalikan. Namun, saya mengalami kesulitan melihat ini sebagai benar negatif mengingat bahwa jika itu adalah bagian dari aplikasi maka perlu didukung entah bagaimana, dan hanya memiliki kolom string yang berisi path sepenuhnya terputus dan memungkinkan file BLOB untuk mendapatkan dihapus tanpa indikasi tentang hal itu di DB (yaitu pointer tidak valid / file hilang). Ini juga memungkinkan file untuk "dihapus" dalam DB tetapi masih ada pada sistem file yang pada akhirnya perlu dibersihkan (yaitu sakit kepala). Tetapi, jika file-file tersebut BESAR, maka mungkin yang terbaik adalah meninggalkan seluruhnya di luar SQL Server kecuali untuk kolom path.
Itu membantu dengan pertanyaan "di dalam atau di luar", tetapi tidak menyentuh pada tabel tunggal vs beberapa pertanyaan tabel. Saya dapat mengatakan bahwa, di luar pertanyaan spesifik ini, pasti ada kasus yang valid untuk memecah tabel menjadi kelompok kolom berdasarkan pola penggunaan. Seringkali ketika seseorang memiliki 50 kolom atau lebih ada beberapa yang sering diakses dan beberapa yang tidak. Beberapa kolom sering ditulis sementara sebagian besar dibaca. Memisahkan kolom yang sering diakses vs yang jarang diakses ke dalam beberapa tabel yang memiliki hubungan 1: 1 cukup sering menguntungkan karena mengapa membuang ruang dalam Buffer Pool untuk data yang mungkin tidak Anda gunakan (mirip dengan mengapa menyimpan gambar besar secara teratur
VARBINARY(MAX)
kolom adalah masalah)? Anda juga meningkatkan kinerja kolom yang sering diakses dengan mengurangi ukuran baris dan karenanya memasang lebih banyak baris ke halaman data, menjadikan pembacaan (baik fisik dan logis) lebih efisien. Tentu saja, Anda juga memperkenalkan beberapa inefisiensi dengan perlu menduplikasi PK, dan sekarang kadang-kadang Anda harus bergabung dengan dua tabel, yang juga menyulitkan (bahkan jika hanya sedikit) beberapa pertanyaan.Jadi, ada beberapa pendekatan yang bisa Anda ambil, dan apa yang terbaik tergantung pada lingkungan Anda dan apa yang ingin Anda capai.
Tidak sesederhana itu. Anda dapat menemukan beberapa info bagus di sini, Berapa Ukuran Pointer LOB untuk (MAX) Jenis Seperti Varchar, Varbinary, Etc? , tetapi dasarnya adalah:
TEXT
,,NTEXT
danIMAGE
tipe data (secara default): 16 byte pointerVARCHAR(MAX)
,NVARCHAR(MAX)
,VARBINARY(MAX)
(Secara default):sumber
Jika data harus disimpan dalam SQL Server untuk alasan apa pun saya dapat memikirkan beberapa manfaat untuk menyimpannya dalam tabel terpisah. Beberapa lebih meyakinkan daripada yang lain.
Menempatkan data dalam tabel terpisah berarti Anda dapat menyimpannya dalam database terpisah. Ini dapat memiliki keuntungan untuk pemeliharaan terjadwal. Misalnya, Anda
DBCC CHECKDB
hanya dapat berjalan di database yang berisi data BLOB.Jika Anda tidak selalu memasukkan lebih dari 8000 byte ke dalam BLOB, maka dimungkinkan untuk disimpan dalam baris untuk beberapa baris. Anda mungkin tidak menginginkannya karena itu akan memperlambat permintaan yang mengakses data menggunakan indeks berkerumun bahkan jika kolom tidak diperlukan oleh kueri. Menempatkan data dalam tabel terpisah menghilangkan risiko ini.
Ketika disimpan dari baris SQL Server menggunakan pointer hingga 24 byte untuk menunjuk ke halaman baru. Itu memakan ruang dan membatasi jumlah kolom BLOB yang bisa Anda tambahkan ke satu tabel. Lihat jawaban srutzky untuk lebih jelasnya.
Indeks toko kolom berkerumun tidak dapat didefinisikan pada tabel yang berisi kolom BLOB. Batasan ini telah dihapus akan dihapus di SQL Server 2017.
Jika Anda akhirnya memutuskan bahwa data harus dipindahkan di luar SQL Server mungkin lebih mudah untuk melakukan perubahan itu jika data sudah dalam tabel terpisah.
sumber