Kapan menggunakan TINYINT melalui INT?

91

Secara umum, saya selalu menggunakan Ints. Saya tahu bahwa secara teori ini bukan praktik terbaik, karena Anda harus menggunakan tipe data terkecil yang akan dijamin untuk menyimpan data.

Misalnya, lebih baik digunakan tinyintketika Anda tahu bahwa satu-satunya data yang akan Anda simpan adalah 1, 0 atau nol (dengan kemungkinan sangat kecil untuk memperluasnya menjadi 2 atau 3 nanti).

Namun, satu-satunya alasan saya tahu untuk melakukan ini adalah untuk tujuan penyimpanan - menggunakan 1 byte berturut-turut, bukan 4 byte.

Apa dampak menggunakan tinyint(atau smallintbahkan bigint) lebih dari sekadar int, selain menghemat ruang pada hard drive Anda?

Richard
sumber
2
Ini adalah pertanyaan yang sangat bagus (+1). MySQL memiliki SELECT ... PROCEDURE ANALYZE () yang sebenarnya merekomendasikan tipe data terkecil yang harus dimiliki tabel untuk SELECT yang diberikan. Itulah sebagian inspirasi di balik jawaban saya.
RolandoMySQLDBA
3
Pertanyaan yang bagus, tapi tepatnya rentang tinyint adalah 0-255. Bidang bit adalah 0 atau 1 (atau NULL). Biaya penyimpanan untuk tinyint adalah 1 byte. Setiap bidang 8 bit dalam sebuah tabel akan dikenakan biaya penyimpanan 1 byte. msdn.microsoft.com/en-us/library/ms187745.aspx dan msdn.microsoft.com/en-us/library/ms177603.aspx
billinkc
@ Billinkc Benar. Itu sebabnya saya menyebutkan kemungkinan memperluas kolom untuk memasukkan nilai 2 atau 3. Jika Anda memasukkan 2 atau 3, Anda harus menggunakan tinyint (pada skala yang sangat kecil).
Richard
1
"Misalnya, lebih baik menggunakan tinyint ketika Anda tahu bahwa satu-satunya data yang akan Anda simpan adalah 1, 0 atau null (dengan kemungkinan sangat kecil untuk memperluasnya menjadi 2 atau 3 nanti)." Saya akan menggunakan ENUM untuk hal semacam itu. Ini disimpan sebagai bitfields, dan seperti yang banyak orang lain tunjukkan di sini, penghematan kecil per catatan menambah penghematan besar pada seluruh database - bahkan lebih jika kolom diindeks.
2
@ user6665 I'd use an ENUM for such a thing.Tidak di SQL Server, Anda tidak akan, karena tidak ada enumerasi dalam bentuk apa pun.
underscore_d

Jawaban:

92

Ruang disk murah ... bukan itu intinya!

Berhenti berpikir dalam hal ruang penyimpanan, alih-alih pikirkan tentang kolam penyangga dan bandwidth penyimpanan . Pada akhirnya, cache CPU dan bandwidth bus memori . Artikel yang ditautkan adalah bagian dari seri yang menyoroti masalah-masalah dengan pemilihan kunci berkerumun yang buruk (INT vs GUID vs Sequential GUID) tetapi menyoroti perbedaan yang bisa dihasilkan oleh byte.

Pesan utama adalah masalah desain. Perbedaannya tidak akan muncul dalam database individual pada server yang ditentukan secara tepat sampai Anda menekan wilayah VLDB tetapi jika Anda dapat menyimpan beberapa byte, mengapa tidak melakukannya.

Saya teringat akan lingkungan yang dijelaskan dalam pertanyaan sebelumnya . 400+ basis data, mulai dari ukuran 50mb-50GB, per contoh SQL. Menggosok beberapa byte per rekaman, per tabel, per basis data di lingkungan itu dapat membuat perbedaan yang signifikan.

Mark Storey-Smith
sumber
29

Selain jawaban lain ...

Baris dan entri indeks disimpan dalam halaman 8k. Jadi sejuta baris pada 3 byte per baris bukan 3 MB pada disk: ini mempengaruhi jumlah baris per halaman ("kepadatan halaman").

Hal yang sama berlaku untuk nvarchar ke varchar, smalldatetime ke datetime, int ke tinyint dll

Edit, Juni 2013

http://sqlblog.com/blogs/joe_chang/archive/2013/06/16/load-test-manifesto.aspx

Artikel ini menyatakan

Kriteria penting adalah kardinalitas dan rasio halaman ke baris.

Jadi, pilihan tipe data penting

gbn
sumber
5
Poin bagus. Contoh kasus terburuk absolut adalah baris 4028 byte yang terdiri dari kolom dengan panjang tetap yang sama yang ingin Anda tambahkan kolom. Menambahkan smallint akan membawa Anda ke 4030 (2 baris per halaman) tetapi sebuah int mendorong Anda melewati batas (1 baris per halaman, 4028 byte terbuang per halaman).
Mark Storey-Smith
Saya pernah melakukan tes kinerja pada int vs bigint. Menyimpan 1 juta catatan, membandingkan waktu dan penyimpanan, dan mengambilnya satu per satu, sekali lagi mengukur kinerja. Saya tidak melihat perbedaan besar. Saya akan melakukan tes kinerja yang sama untuk int vs tinyint. Saya benar-benar berpikir itu dapat diabaikan untuk 80% dari aplikasi, menghasilkan tipe data yang lebih konsisten, dan biaya perawatan yang lebih rendah.
Saeed Neamati
1
@ SaeedNeamati Anda mungkin ingin membaca ulang artikel dari jawaban Mark (" Pernahkah Anda mendengar ... mari kita selesaikan ini - kita akan khawatir tentang kinerja nanti? ... Saya mendengar ini sepanjang waktu ... ") dan gbn ada di sini . Saya pikir yang dibawa pulang adalah bahwa setiap pilihan yang tidak efisien akan menunjukkan garis-garisnya pada skala yang tepat, dan isi OP tidak salah.
ruffin
14

Bukan hanya penyimpanan meja yang menjadi pertimbangan. Jika Anda menggunakan indeks di mana kolom int adalah bagian dari kunci majemuk, Anda tentu ingin halaman indeks selengkap mungkin, ini menjadi hasil entri indeks sekecil mungkin.

Saya pasti berharap menemukan bahwa memeriksa entri indeks di halaman BTREE akan sedikit lebih cepat dengan tipe data yang lebih kecil. Namun, setiap VARCHAR yang terlibat dalam entri indeks akan mengimbangi (membatalkan) keuntungan kinerja dari penggunaan TINYINT atas INT.

Meskipun demikian, jika entri indeks memiliki entri majemuk dan semua adalah bilangan bulat, semakin kecil bilangan bulat itu, semakin baik dan semakin cepat.

RolandoMySQLDBA
sumber
13

Semua hal menjadi semakin rumit saat database semakin besar:

  • jendela pemeliharaan perlu diperbesar atau dijadwal ulang
  • backup (backup penuh akhir hari menjadi pemakan waktu yang absurd, jadi Anda memerlukan diferensial atau bahkan mencatat backup dan melakukan full seminggu sekali, mungkin sebulan sekali)
  • pertunjukan maintanances menjadi pemakan waktu (membuat indeks pada tabel multi-juta-baris tidak membutuhkan waktu sepele untuk dieksekusi) dan perlu dijadwal ulang dan menjadi lebih buruk jika meja ...
  • Dan mentransmisikan cadangan 100Gb melalui jaringan bukanlah apa yang saya sebut sepotong kue - khususnya jika jaringan (untuk beberapa alasan yang tidak diketahui) keras kepala saat menjatuhkan koneksi pada tanda 75Gb ... (terjadi pada instalasi saya sedang mengerjakan itu sedang mencadangkan ke drive yang dipetakan di jaringan - jaringan) ...

Dan apa tipe data yang harus dilakukan dengan itu? SEGALA SESUATU. Menggunakan ukuran baris yang lebih besar dari yang diperlukan membuat halaman database diisi sebelum dari yang dibutuhkan atau bahkan membuang-buang ruang jika ukuran baris sedemikian rupa sehingga tidak lebih dari satu catatan yang dapat direkam pada halaman. Hasilnya adalah lebih banyak halaman yang diperlukan untuk ditulis dan dibaca, lebih banyak memori RAM digunakan untuk cache itu (catatan yang lebih besar membutuhkan memori yang lebih besar). Dan karena tipe data Anda ditentukan lebih besar dari yang dibutuhkan dari disk, indeks Anda akan mengalami masalah yang sama - khususnya jika Anda mengelompokkan 2 kunci kolom BIGINT komposit tersebut karena indeks lain yang dibuat akan menyalin kunci primer secara implisit pada definisi mereka.

Jika Anda tahu bahwa beberapa kolom dalam tabel yang akan memiliki jutaan baris atau bahkan sedikit tabel yang akan FK'ed ke multi-juta-baris yang tidak memerlukan integer 4 byte untuk menyimpan data mereka, tetapi 2 byte akan cukup - gunakan SMALLINT . Jika nilai dalam kisaran 0-255 sudah cukup, TINYINT . Bendera Ya / Tidak? Ada BIT .

Fabricio Araujo
sumber
9

Sementara untuk tinyintvs intada perbedaan yang jelas seperti ruang disk, pemisahan halaman dan waktu perawatan, tidak akan ada untuk semua ini varchar.

Jadi mengapa tidak mendeklarasikan semua bidang teks sebagai varchar(4000), karena bagaimanapun juga hanya akan menggunakan ruang yang dibutuhkan? Terlebih lagi Anda akan dijamin bahwa data Anda tidak akan pernah terpotong.

Jawabannya tentu saja:

  1. Klarifikasi niat Anda (karena tidak ada yang akan mengerti mengapa bidang nama harus 4000 karakter)
  2. Validasi karena Anda ingin memastikan tidak ada yang memasukkan seluruh biografi sebagai namanya.

Alasan yang sama juga berlaku untuk ini tinyint.

halo yoel
sumber
3
Ini adalah utas yang lebih lama, tetapi klarifikasi dan validasi bukan satu-satunya alasan. Jika Anda memiliki VARCHAR (4000) untuk sesuatu yang seharusnya VARCHAR (20), rencana kueri akan berpikir bahwa kebutuhan memori dan CPU Anda banyak kelipatan dari yang seharusnya dalam hal kolom tersebut. Saya belum meluangkan waktu untuk melakukan ini, tetapi saya menduga Anda mungkin dapat melihat ini dengan melihat rencana permintaan untuk VARCHAR (20) dan kemudian beralih ke VARCHAR (4000) dan memeriksa perkiraan biaya.
3
@GeorgeShouse Demonstrasi tentang hal itu di sini
Martin Smith