MySQL: VARCHAR Besar vs. TEKS?

847

Saya punya tabel pesan di MySQL yang merekam pesan antar pengguna. Terlepas dari id dan tipe pesan tipikal (semua tipe integer) saya perlu menyimpan teks pesan yang sebenarnya sebagai VARCHAR atau TEXT. Saya menetapkan batas front-end 3000 karakter yang berarti pesan tidak akan pernah dimasukkan ke db lebih lama dari ini.

Apakah ada alasan untuk menggunakan VARCHAR (3000) atau TEXT? Ada sesuatu tentang hanya menulis VARCHAR (3000) yang terasa agak kontra-intuitif. Saya telah melalui posting serupa lainnya di Stack Overflow tetapi akan lebih baik untuk mendapatkan tampilan spesifik untuk jenis penyimpanan pesan umum ini.

Tom
sumber
28
Agak tua, tetapi saya datang ke sini karena saya mengalami masalah yang membuat saya memikirkan hal ini. Dalam kasus saya, bentuk front-end saya terbatas pada 2.000 karakter tetapi penyandian yang tersirat dalam metode penyimpanan saya menyandikan karakter internasional sebagai beberapa karakter (yang tampaknya dapat berkisar antara 3 - 12 per karakter). Jadi 2.000 saya tiba-tiba menjadi 24.000. Sesuatu untuk dipikirkan ...
James S
3
Saya telah menemukan teks secara signifikan lebih cepat untuk banyak sisipan bersamaan.
Ray S.
1
@JamesS: utf8mb4 ...>. <
tidak dapat dibagi
10
@RickJames mempertimbangkan untuk memposting jawaban yang diperbarui, daripada menutup pertanyaan
Yvette
3
@YvetteColomb - Saya menambahkan Jawaban. Saya terutama ingin menyingkirkan Jawaban yang Diterima karena sudah ketinggalan zaman . Saya datang ke T&J karena seseorang mengutip info yang salah, mengatakan "754 upvotes, jadi pasti benar". OK, saya mengedit jawaban yang Disetujui juga. (Meskipun itu terasa tidak pantas.)
Rick James

Jawaban:

812
  • TEXTdan BLOB mungkin dengan disimpan dari meja dengan tabel hanya memiliki pointer ke lokasi penyimpanan yang sebenarnya. Di mana itu disimpan tergantung pada banyak hal seperti ukuran data, ukuran kolom, row_format, dan versi MySQL.

  • VARCHARdisimpan sejajar dengan tabel. VARCHARlebih cepat ketika ukurannya masuk akal, pengorbanannya akan lebih cepat tergantung pada data dan perangkat keras Anda, Anda ingin membandingkan skenario dunia nyata dengan data Anda.

MindStalker
sumber
149
+1: VARCHAR (disimpan sebaris) biasanya lebih cepat JIKA data sering diambil (termasuk oleh sebagian besar kueri). Namun, untuk volume data yang besar yang biasanya tidak diambil (yaitu, tidak direferensikan oleh permintaan apa pun), maka mungkin lebih baik untuk tidak memiliki data yang disimpan inline. Ada batas atas pada ukuran baris, untuk data yang disimpan sebaris.
spencer7593
22
@Pacerier: manfaat sebenarnya dari menghindari penyimpanan "inline" adalah peningkatan jumlah baris yang dapat disimpan dalam sebuah blok, yang berarti baris tabel menempati lebih sedikit blok dalam cache buffer InnoDB (jejak memori lebih kecil), dan berarti lebih sedikit blok yang akan ditransfer ke dan dari disk (mengurangi I / O). Tapi, ini hanya manfaat kinerja jika kolom yang disimpan "off row" sebagian besar tidak direferensikan oleh kueri. Jika kolom "off row" itu dirujuk oleh sebagian besar kueri, manfaat itu sebagian besar menguap. Sebaris disukai jika kolom sesuai dengan ukuran baris maks dan sering direferensikan.
spencer7593
232
"VARCHAR lebih cepat ketika ukurannya masuk akal". Berapakah jumlah karakter yang "masuk akal", 100? 1000? 100.000?
tim peterson
126
Jawaban ini tidak benar untuk InnoDB. Baik VARCHAR dan BLOB / TEXT disimpan sejajar dengan kolom lain jika nilai pada baris yang diberikan sesuai dengan ukuran halaman (16KB dan setiap halaman harus memiliki setidaknya dua baris). Jika string terlalu besar untuk itu, itu meluap ke halaman tambahan. Lihat mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb untuk penjelasan terperinci.
Bill Karwin
15
@ BillKarwin ... Jika saya memahami dengan benar maka seharusnya tidak ada perbedaan kinerja antara varchardan blob/ textpada InnoDB untuk item teks kecil? Jadi akan kemudian bijaksana untuk hanya membuat setiap varcharsatu textjenis dan membiarkan DB mengelola inline vs overflow?
ryvantage
475

Bisakah Anda memprediksi berapa lama input pengguna?

VARCHAR (X)

Kasus: nama pengguna, email, negara, subjek, kata sandi


TEKS

Kasus: pesan, email, komentar, teks berformat, html, kode, gambar, tautan


MEDIUMTEXT

Kasus: tubuh json besar, buku pendek sampai sedang, string csv


PANJANG

Kasus: buku teks, program, tahun file log, harry potter dan piala api, logging penelitian ilmiah

Michael J. Calkins
sumber
8
Prediktabilitas benar-benar item sampingan di sini. Sebenarnya panjang maksimum yang diharapkan yang seharusnya menjadi faktor penentu. Item yang Anda sebutkan lebih mudah diprediksi hanya karena itu lebih pendek daripada yang lain.
Andrew Barber
30
@ andrew-tukang cukur Itulah maksud saya. Semua posting lain menjelaskan dengan baik tentang perbedaan tetapi tidak tentang situasi ketika Anda benar-benar harus membuat pilihan di antara keduanya. Saya mencoba menunjukkan penggunaan varchar karena dapat diprediksi pendek adalah pilihan yang baik dan menggunakan teks untuk panjang sembarang adalah pilihan yang baik.
Michael J. Calkins
1
Jika semua kolom pendek dan dapat diprediksi (mis: alamat MAC, IMEI, dll ... adalah hal-hal yang tidak pernah berubah) maka gunakan kolom CHAR dan Anda dapat membuat ukuran baris Anda tetap, yang seharusnya mempercepat banyak hal jika menggunakan MyISAM, mungkin juga InnoDb meskipun saya tidak yakin tentang itu.
Matt
1
@ MichaelJ.Calkins Hal yang terjadi di MySQL 5.6. Sekarang Anda juga memiliki pencarian teks lengkap di InnoDB. Lihat dev.mysql.com/doc/refman/5.6/en/fulltext-search.html
PhoneixS
7
Batas karakter: TINYTEXT: 255; TEXT: 65.535; MEDIUMTEXT: 16.777.215; PANJANG: 4.294.967.29.
Victor Stoddard
219

Hanya untuk mengklarifikasi praktik terbaik:

  1. Pesan berformat teks hampir selalu disimpan sebagai TEXT (akhirnya panjangnya sewenang-wenang)

  2. Atribut string harus disimpan sebagai VARCHAR (nama pengguna tujuan, subjek, dll ...).

Saya mengerti bahwa Anda memiliki batas ujung depan, yang sangat bagus sampai tidak. * nyengir * Caranya adalah menganggap DB terpisah dari aplikasi yang terhubung dengannya. Hanya karena satu aplikasi membatasi data, tidak berarti bahwa data secara intrinsik terbatas.

Ada apa dengan pesan itu sendiri yang memaksa mereka untuk tidak pernah lebih dari 3000 karakter? Jika itu hanya kendala aplikasi yang sewenang-wenang (misalnya, untuk kotak teks atau sesuatu), gunakan TEXTbidang di lapisan data.

James
sumber
Apa artinya "yang bagus sampai tidak"? Apa yang dimaksud dengan "tidak"?
Pacerier
7
@Pacerier Untuk memberi Anda contoh "bukan", James kemungkinan akan berbicara tentang: Ambil contoh Twitter, yang hingga baru-baru ini memiliki batas 140 karakter pada PM. Mereka memutuskan itu tidak masuk akal lagi dan memilih untuk menghapus batas itu sepenuhnya. Jika mereka tidak berpikir ke depan tentang itu (yang saya yakin mereka mungkin lakukan ...) mereka akan menjalankan skenario yang diuraikan di atas.
PaulSkinner
9
Saya hanya meletakkan basis data baru kami, dan saya berasumsi tidak ada yang bisa memasukkan lebih dari 2000 karakter ke dalam kotak komentar kecil kami, dan kemudian, seperti yang dicatat James, malam ini tiba-tiba "tidak apa-apa" karena pengguna memasukkan komentar yang sangat valid dengan panjang 2600 karakter. Saya menggunakan varchar (2000) berpikir itu tidak mungkin lebih lama dari itu, dan saya salah. jadi ya, itu bagus sampai tidak. Dalam kasus kami itu hanya butuh beberapa hari untuk terwujud. Aturan di bawah ini, Michael J. Calkins, saya pikir saya akan gunakan mulai sekarang. teks untuk pesan, komentar.
Lizardx
1
@Pacerier "bagus sekali sampai tidak bagus". Dengan kata lain, ia bekerja hampir sepanjang waktu dan luar biasa ... kecuali situasi luar biasa yang tidak begitu hebat.
Penebusan Terbatas
@Pacerier contoh lain yang menarik disebutkan dalam komentar dari jawaban yang dipilih, pada dasarnya ia memiliki batas front-end 2.000 karakter tetapi karakter yang diperkenalkan berada dalam codepage yang pada kenyataannya menggunakan lebih banyak byte daripada huruf normal, database-nya akhirnya membutuhkan ruang untuk 24k karakter hanya karena dia harus memperhitungkan ukuran byte sebenarnya dari karakter yang diperkenalkan.
RaptorX
32

Penafian: Saya bukan ahli MySQL ... tapi ini adalah pemahaman saya tentang masalah ini.

Saya pikir TEXT disimpan di luar baris mysql, sementara saya pikir VARCHAR disimpan sebagai bagian dari baris. Ada panjang baris maksimum untuk baris mysql .. sehingga Anda dapat membatasi berapa banyak data lain yang dapat Anda simpan dalam satu baris dengan menggunakan VARCHAR.

Juga karena VARCHAR membentuk bagian dari baris, saya menduga bahwa permintaan melihat bidang itu akan sedikit lebih cepat daripada yang menggunakan potongan TEXT.

Michael Anderson
sumber
38
Batas panjang baris adalah 65.535 byte [ dev.mysql.com/doc/refman/5.0/id/column-count-limit.html ]. Jika kolom Anda dikodekan utf8, itu artinya varcharkolom 3000 karakter dapat memakan waktu hingga 9000 byte.
Jan Fabry
7
Karakter UTF-8 dapat mencapai 4 byte, jadi saya pikir maksud Anda 12.000 byte (kecuali ada beberapa hal MySQL yang tidak saya mengerti di sini).
raylu
13
@raylu UTF-8 MySQL adalah "UTF-8 palsu" karena hanya mendukung 3 byte per karakter maks, jadi tidak ada cara untuk secara langsung menyimpan karakter unicode di luar pesawat BMP di UTF-8 MySQL. Ini diperbaiki di MySQL 5.5.
Pacerier
2
Saya percaya bahwa pernyataan ini hanya berlaku untuk MyISAM. Saya tidak dapat menemukan sumber yang pasti, tetapi saya percaya bahwa InnoDB juga menyimpan TEXTinline di tabel.
dotancohen
2
@dotancohen Saya menemukan sumber di sini menjelaskan bahwa menyimpan data panjang variabel menggunakan InnoDB dapat bervariasi (dapat disimpan secara eksternal atau inline dalam baris) mysqlserverteam.com/ secara eksternal
stored
30

Jawaban singkat: Tidak ada perbedaan praktis, kinerja, atau penyimpanan.

Jawaban panjang:

Pada dasarnya tidak ada perbedaan (dalam MySQL) antara VARCHAR(3000)(atau batas besar lainnya) dan TEXT. Yang pertama akan dipotong pada 3000 karakter ; yang terakhir akan dipotong pada 65535 byte . (Saya membuat perbedaan antara byte dan karakter karena karakter dapat mengambil banyak byte.)

Untuk batas yang lebih kecil VARCHAR, ada beberapa kelebihan di atas TEXT.

  • "lebih kecil" berarti 191, 255, 512, 767, atau 3072, dll, tergantung pada versi, konteks, dan CHARACTER SET.
  • INDEXesterbatas pada seberapa besar kolom dapat diindeks. (767 atau 3072 byte ; ini tergantung versi dan pengaturan)
  • Tabel perantara yang dibuat oleh kompleks SELECTsditangani dengan dua cara berbeda - MEMORY (lebih cepat) atau MyISAM (lebih lambat). Ketika kolom 'besar' terlibat, teknik yang lebih lambat akan dipilih secara otomatis. (Perubahan signifikan datang dalam versi 8.0; jadi butir ini dapat berubah.)
  • Terkait dengan item sebelumnya, semua TEXTtipe data (sebagai lawan dari VARCHAR) melompat langsung ke MyISAM. Artinya, TINYTEXTsecara otomatis lebih buruk untuk tabel temp yang dihasilkan daripada yang setara VARCHAR. (Tapi ini membawa diskusi ke arah ketiga!)
  • VARBINARYseperti VARCHAR; BLOBseperti TEXT.

Bantahan terhadap jawaban lain

Pertanyaan asli menanyakan satu hal (tipe data mana yang digunakan); jawaban yang diterima menjawab hal lain (penyimpanan tidak direkam). Jawaban itu sudah ketinggalan zaman.

Ketika utas ini dimulai dan dijawab, hanya ada dua "format baris" di InnoDB. Segera setelah itu, dua format lagi ( DYNAMICdan COMPRESSED) diperkenalkan.

Lokasi penyimpanan untuk TEXTdan VARCHAR()didasarkan pada ukuran , bukan pada nama tipe data . Untuk diskusi terbaru penyimpanan on / off-record kolom teks / gumpalan besar, lihat ini .

Rick James
sumber
1
Beberapa wawasan yang bagus di sini. Ini harus menjadi jawaban yang diterima.
Kosta Kontos
2
@KostaKontos - Terima kasih atas pujian dan perbaikan kesalahan ketiknya. Ketika saya melihat kebutuhan untuk jawaban yang lebih baik, saya akan menambahkan jawaban, bahkan jika 8 tahun dan 800 terlambat mendukung.
Rick James
7

Jawaban sebelumnya tidak cukup menekankan pada masalah utama: bahkan dalam pertanyaan yang sangat sederhana seperti

(SELECT t2.* FROM t1, t2 WHERE t2.id = t1.id ORDER BY t1.id) 

tabel sementara dapat diminta, dan jika suatu VARCHARbidang dilibatkan, itu dikonversi ke CHARbidang dalam tabel sementara. Jadi, jika Anda memiliki di meja Anda mengatakan 500 000 baris dengan VARCHAR(65000)bidang, kolom ini saja akan menggunakan 6,5 * 5 * 10 ^ 9 byte. Tabel temp semacam itu tidak dapat ditangani dalam memori dan ditulis ke disk. Dampaknya bisa menjadi bencana.

Sumber (dengan metrik): https://nicj.net/mysql-text-vs-varchar-performance/ (Ini merujuk pada penanganan TEXTvs VARCHARpada "standar" (?) Mesin penyimpanan MyISAM. Mungkin berbeda pada yang lain, mis., InnoDB.)

Maks
sumber
3
InnoDB: Hal yang sama berlaku melalui versi 5.7. Dengan 8.0, temps varchar adalah panjang variabel.
Rick James
3

Ada perbedaan BESAR antara VARCHAR dan TEXT. Sementara bidang VARCHAR dapat diindeks, bidang TEXT tidak bisa. Bidang tipe VARCHAR disimpan inline saat TEXT disimpan offline, hanya pointer ke data TEXT yang sebenarnya disimpan dalam catatan.

Jika Anda harus mengindeks bidang Anda untuk pencarian yang lebih cepat, perbarui atau hapus daripada pergi untuk VARCHAR, tidak peduli seberapa besar. VARCHAR (10000000) tidak akan pernah sama dengan bidang TEXT karena kedua tipe data ini berbeda.

  • Jika Anda menggunakan bidang Anda hanya untuk pengarsipan
  • Anda tidak peduli tentang pengambilan kecepatan data
  • Anda peduli tentang kecepatan tetapi Anda akan menggunakan operator '% LIKE%' dalam permintaan pencarian Anda sehingga pengindeksan tidak akan banyak membantu
  • Anda tidak dapat memprediksi batas panjang data

daripada pergi untuk TEKS.

Viktor Joras
sumber
Info yang menyesatkan sebagian: kolom TEKS tidak dapat diindeks secara keseluruhan. Ketika Anda memasukkan kolom TEKS dalam indeks Anda harus menentukan panjangnya. Juga VARCHAR tidak dapat diindeks secara keseluruhan dalam kasus VARCHAR> 255 karena ada panjang maksimal pada ukuran indeks.
eRadical
2

Varchar adalah untuk data kecil seperti alamat email, sedangkan Teks untuk data yang jauh lebih besar seperti artikel berita, Blob untuk data biner seperti gambar.

Kinerja Varchar lebih kuat karena berjalan sepenuhnya dari memori, tetapi ini tidak akan menjadi masalah jika data terlalu besar seperti varchar(4000)misalnya.

Teks, di sisi lain, tidak menempel ke memori dan dipengaruhi oleh kinerja disk, tetapi Anda dapat menghindarinya dengan memisahkan data teks dalam tabel terpisah dan menerapkan kueri gabung kiri untuk mengambil data teks.

Blob jauh lebih lambat jadi gunakan hanya jika Anda tidak memiliki banyak data seperti 10.000 gambar yang akan menelan biaya 10.000 catatan.

Ikuti tips ini untuk kecepatan dan kinerja maksimum:

  1. Gunakan varchar untuk nama, judul, email

  2. Gunakan Teks untuk data besar

  3. Pisahkan teks dalam tabel yang berbeda

  4. Gunakan kueri Gabung Kiri pada ID seperti nomor telepon

  5. Jika Anda akan menggunakan Blob, terapkan tip yang sama seperti pada Teks

Ini akan membuat kueri biaya milidetik pada tabel dengan data> 10 M dan ukuran hingga 10GB dijamin.

Creative87
sumber