Implikasi kinerja dari ukuran MySQL VARCHAR

45

Apakah ada perbedaan kinerja dalam MySQL antara ukuran varchar? Sebagai contoh, varchar(25)dan varchar(64000). Jika tidak, adakah alasan untuk tidak mendeklarasikan semua varchars dengan ukuran maksimal hanya untuk memastikan Anda tidak kehabisan ruangan?

BenV
sumber
3
+1 pertanyaan ini berlaku serupa dengan semua DBMS. Pengamatan saya banyak ukuran varchar cenderung tumbuh.
bernd_k
5
Bukan MySQL, tetapi posting blog ini oleh Depesz dapat menjawab pertanyaan Anda untuk PostgreSQL .
xenoterracide

Jawaban:

29

Anda harus menyadari pengorbanan menggunakan CHAR vs VARCHAR

Dengan bidang CHAR, apa yang Anda alokasikan adalah persis apa yang Anda dapatkan. Misalnya, CHAR (15) mengalokasikan dan menyimpan 15 byte, tidak peduli bagaimana karakter yang Anda tempatkan di bidang. Manipulasi string sederhana dan mudah karena ukuran bidang data benar-benar dapat diprediksi.

Dengan bidang VARCHAR, Anda mendapatkan cerita yang sama sekali berbeda. Misalnya VARCHAR (15) sebenarnya mengalokasikan secara dinamis hingga 16 byte, hingga 15 untuk data dan, setidaknya, 1 byte tambahan untuk menyimpan panjang data. Jika Anda memiliki string 'halo' untuk menyimpan yang akan mengambil 6 byte, bukan 5. Manipulasi string harus selalu melakukan semacam pemeriksaan panjang dalam semua kasus.

Imbalan lebih jelas ketika Anda melakukan dua hal:
1. Menyimpan jutaan atau miliaran baris
2. Kolom pengindeksan yang baik CHAR atau VARCHAR

TRADEOFF # 1

Jelas, VARCHAR memegang keuntungan karena data panjang variabel akan menghasilkan baris yang lebih kecil dan, dengan demikian, file fisik yang lebih kecil.

TRADEOFF # 2

Karena bidang CHAR memerlukan manipulasi string lebih sedikit karena lebar bidang tetap, pencarian indeks terhadap bidang CHAR rata-rata 20% lebih cepat daripada bidang VARCHAR. Ini bukan dugaan saya. Buku MySQL Database Design and Tuning melakukan sesuatu yang luar biasa pada tabel MyISAM untuk membuktikan ini. Contoh dalam buku ini melakukan sesuatu seperti berikut:

ALTER TABLE tblname ROW_FORMAT=FIXED;

Kekuatan pengarah ini adalah VARCHAR untuk berperilaku sebagai CHAR. Saya melakukan ini di pekerjaan saya sebelumnya pada tahun 2007 dan mengambil meja 300GB dan mempercepat pencarian indeks sebesar 20%, tanpa mengubah apa pun. Ini berfungsi seperti yang dipublikasikan. Namun, itu memang menghasilkan tabel hampir dua kali lipat, tetapi itu hanya kembali ke tradeoff # 1.

Anda bisa menganalisis data yang disimpan untuk melihat apa yang direkomendasikan MySQL untuk definisi kolom. Jalankan saja berikut ini di tabel mana saja:

SELECT * FROM tblname PROCEDURE ANALYSE();

Ini akan melintasi seluruh tabel dan merekomendasikan definisi kolom untuk setiap kolom berdasarkan data yang dikandungnya, nilai bidang minimum, nilai bidang maksimum, dan sebagainya. Terkadang, Anda hanya perlu menggunakan akal sehat dengan merencanakan CHAR vs VARCHAR. Ini adalah contoh yang bagus:

Jika Anda menyimpan alamat IP, mask untuk kolom seperti itu paling banyak 15 karakter (xxx.xxx.xxx.xxx). Saya akan melompat tepat di CHAR (15) dalam sekejap karena panjang alamat IP tidak akan banyak berbeda dan kompleksitas tambahan dari manipulasi string dikontrol oleh byte tambahan. Anda masih bisa melakukan PROSEDUR ANALISIS () terhadap kolom tersebut. Bahkan mungkin merekomendasikan VARCHAR. Uang saya masih di CHAR atas VARCHAR dalam hal ini.

Masalah CHAR vs VARCHAR hanya dapat diselesaikan melalui perencanaan yang tepat. Dengan kekuatan besar datang tanggung jawab besar (klise tapi benar)

RolandoMySQLDBA
sumber
4
Jika Anda menyimpan alamat IP, saya tidak melihat alasan untuk menyimpannya selain dari int. Itu semua alamat IP. Banyak bahasa memiliki semacam fungsi ip2int. Jika Anda ingin kenyamanan panggilan baris perintah, tidak sulit untuk membuat prosedur tersimpan untuk mengonversi ABCD: Pow (256,3) + b pow (256,2) + c * 256 + d
atxdba
1
Err lebih tepatnya, saya kira mysql memiliki fungsi ip2int sendiri: INET_ATON
atxdba
3
@ atxdba: Inti dari jawaban saya hanya menggunakan CHAR vs VARCHAR. Saya hanya menggunakan IP sebagai contoh karena ukuran karakter string lebih dekat ke 15. Jadi, pembulatan ukuran CHAR yang stabil dalam mendukung VARCHAR hanyalah contoh demi pertanyaan itu sendiri. Komentar Anda tentang cara yang lebih baik untuk mewakili alamat IP cukup valid dan masuk akal.
RolandoMySQLDBA
CHAR (15) mengalokasikan 15 karakter , bukan byte . Untuk utf8, itu adalah 45 byte .
Rick James
2
Meskipun ini adalah jawaban yang baik tentang perbandingan CHAR / VARCHAR, pertanyaannya adalah tentang berbagai ukuran VARCHAR.
Kolektor
13

Jawabannya sebenarnya agak rumit. Versi singkatnya: ada perbedaan .

  1. Saat membuat tabel sementara untuk menyaring hasil (misalnya GROUP BYpernyataan), panjang penuh akan dialokasikan.

  2. Protokol kawat (mengirim baris ke klien) kemungkinan akan mengalokasikan panjang yang lebih besar.

  3. Mesin penyimpanan mungkin / mungkin tidak menerapkan varchar yang tepat.

Untuk (2) saya akui protokol kawat bukanlah sesuatu yang saya kenal dengan akrab, tetapi saran umum di sini adalah mencoba dan menerapkan setidaknya beberapa upaya minimal untuk menebak panjangnya.

Morgan Tocker
sumber
Layak menunjukkan. MySQL 5.7 dapat mengemas nilai dalam buffer penyortiran (panjang variabel). Dijelaskan secara lebih rinci di sini: mysqlserverteam.com/…
Morgan Tocker
9

Sebagian besar jawaban di utas ini berusia 5 tahun, ditulis sebelum InnoDB dan utf8 adalah default. Jadi, izinkan saya memulai lagi ...

Ketika kueri membutuhkan tabel sementara internal, ia mencoba menggunakan MEMORYtabel. Tetapi MEMORY tidak dapat digunakan jika

  • TEXT/ BLOBKolom diambil, bahkan tidak TINYTEXT.
  • VARCHAR lebih besar dari jumlah tertentu, mungkin 512 dalam versi saat ini.

Juga, perhatikan yang VARCHARsdiubah menjadi CHARs. Jadi, VARCHAR(255)dengan CHARACTER SET utf8ekspansi ke 765 byte, terlepas dari apa yang ada di kolom. Kemudian, ini mungkin dipicu:

  • Jika MEMORYtabel menjadi lebih besar dari salah satu max_heap_table_size atau tmp_table_size , itu akan dikonversi ke MyISAM dan berpotensi tumpah ke disk.

Jadi, VARCHAR(25)lebih mungkin untuk tetap MEMORY, maka lebih cepat. (255)tidak sebagus, dan (64000)buruk.

(Di masa depan, temp tables mungkin akan ada InnoDB, dan bagian dari jawaban ini perlu direvisi.)

Rick James
sumber
6

Kolom varchar yang ukurannya membuat kueri di seluruh tabel lebih cenderung menggunakan tabel sementara. Menurut buku MySQL Kinerja Tinggi. Ketika pengoptimal mencoba untuk melihat apakah ia dapat menjalankan kueri ini di memori atau jika ia membutuhkan tabel temp, itu melihat ukuran baris berdasarkan definisi tabel, artinya, untuk kecepatan ia tidak mencoba melihat seberapa banyak karakter 64K Anda benar-benar menggunakan. Inilah sebabnya penulis menyarankan Anda untuk tidak merentangkan definisi itu melampaui nilai-nilai aktual yang mungkin masuk dalam kolom. Jelas, jika Anda mengatur diri sendiri untuk lebih banyak pertanyaan masuk ke tabel temp (bahkan jika ukuran data yang sebenarnya bisa muat dalam RAM) Anda sekarang telah dikenakan hukuman I / O Anda bisa menghindari.

TechieGurl
sumber
Itu perspektif yang sangat segar. Jika ini adalah buku yang Anda rujuk ( amazon.com/MySQL-High-Avilities-Building-Centers/dp/… ), harap cantumkan nomor halaman buku dalam jawaban Anda, karena saya ingin membacanya. +1 !!!
RolandoMySQLDBA
Konyol… KINERJA Tinggi tidak ada: amazon.com/High-Performance-MySQL-Optimation-Replication/dp/… ... nomor halaman 236/237 Ini menjelaskan bagaimana kemurahan hati dalam mendefinisikan kolom varchar bisa menjadi tidak bijaksana. Perlu diingat bahwa buku ini ditulis kembali ketika 5.1 baru saja keluar. Edisi ketiga akan keluar tahun depan untuk memasukkan semua perubahan BESAR di 5,5 jadi mungkin itu akan berubah :)
TechieGurl
Halaman 236 menyebutkan collation milik set char tertentu. Itu bisa jadi agak menjijikkan bagi VARCHAR. Pada halaman 237, Pengaturan untuk komunikasi klien / server bersama dengan Gambar 5-5 pada halaman 238 menunjukkan alasan lain. Proses penerjemahan karakter bolak-balik. Sekali lagi, petualangan jahat lain untuk VARCHAR.
RolandoMySQLDBA
Untuk memperjelas, meskipun bagian ini tidak mengatakan langsung bahwa MySQL akan digunakan untuk membuat ukuran, kita tahu bahwa ketika sebuah operasi membutuhkan tabel sementara yang tabelnya ada di MEMORY Engine dan BAHWA selalu menyimpan tipe string dalam potongan perbaikan sehingga seperti itulah cara yang murah hati definisi dapat menyebabkan tabel temp MEMORY yang diperlukan untuk pergi ke disk sebagai lawan tinggal di RAM
TechieGurl
@RolandoMySQLDBA. Yap ... itu juga ... collation juga menjadi faktor di sini (terutama jika Anda menggunakan UTF-8 dan memiliki karakter non latin) dan itu semua hanya membunuh Anda ketika berhadapan dengan meja mesin memori dan mengarah ke perjalanan yang lebih cepat ke disk
TechieGurl
5

Ini pemahaman saya bahwa bidang yang lebih kecil dapat dimasukkan dalam indeks secara langsung, sedangkan yang lebih panjang tidak bisa. Karena keterbatasan itu, jika Anda ingin string dapat diindeks, saya akan mengatakan agar mereka lebih pendek. Kalau tidak, tidak, karena keduanya sama-sama varchar maka ops seperti sortir atau perbandingan akan beroperasi dalam waktu yang sama, apakah bidangnya 25 atau MAX.

jcolebrand
sumber
3

pastikan Anda tidak kehabisan kamar

Frasa ini menyiratkan bahwa Anda mengajukan pertanyaan karena Anda tidak yakin tentang data yang akan Anda simpan dalam database. Jika itu benar, Anda akan dilayani dengan baik untuk mengetahuinya sesegera mungkin, karena Anda akan membutuhkannya untuk perencanaan kapasitas. Jika Anda mungkin mendapatkan elemen data dengan 7000 karakter, misalnya, Anda perlu tahu karena itu akan memiliki implikasi kinerja pada setiap DBMS.

Karena itu, saya lebih suka memiliki ukuran kolom yang terkait dengan konten yang diharapkan. Misalnya, nomor telepon tidak lebih dari 50 karakter, bahkan jika Anda memasukkan kode negara dan ekstensi. Demikian pula, kode pos atau kode pos kemungkinan besar akan menjadi 20 karakter atau kurang.

Larry Coleman
sumber