Apakah ada perbedaan kinerja yang terukur antara menggunakan INT vs VARCHAR sebagai kunci utama di MySQL? Saya ingin menggunakan VARCHAR sebagai kunci utama untuk daftar referensi (pikirkan US States, Country Codes) dan rekan kerja tidak akan mengalah pada INT AUTO_INCREMENT sebagai kunci utama untuk semua tabel.
Argumen saya, sebagaimana dirinci di sini , adalah bahwa perbedaan kinerja antara INT dan VARCHAR dapat diabaikan, karena setiap referensi kunci asing INT akan memerlukan GABUNG untuk memahami referensi tersebut, kunci VARCHAR akan langsung menyajikan informasi.
Jadi, apakah ada yang punya pengalaman dengan kasus penggunaan khusus ini dan masalah kinerja yang terkait dengannya?
mysql
performance
primary-key
innodb
myisam
Jake McGraw
sumber
sumber
Jawaban:
Anda membuat poin yang bagus bahwa Anda dapat menghindari sejumlah kueri yang digabungkan dengan menggunakan apa yang disebut kunci alami alih - alih kunci pengganti . Hanya Anda yang dapat menilai apakah manfaatnya signifikan dalam aplikasi Anda.
Artinya, Anda bisa mengukur kueri dalam aplikasi Anda yang paling penting untuk menjadi cepat, karena mereka bekerja dengan volume data yang besar atau dieksekusi sangat sering. Jika kueri ini mendapat manfaat dari menghilangkan gabungan, dan tidak menderita dengan menggunakan kunci utama varchar, maka lakukanlah.
Jangan gunakan salah satu strategi untuk semua tabel di database Anda. Kemungkinan dalam beberapa kasus, kunci alami lebih baik, tetapi dalam kasus lain kunci pengganti lebih baik.
Orang lain berpendapat bahwa jarang ada kunci alami yang tidak pernah berubah atau memiliki duplikat, jadi kunci pengganti biasanya bermanfaat.
sumber
Ini bukan tentang kinerja. Ini tentang apa yang membuat kunci utama yang baik. Unik dan tidak berubah dari waktu ke waktu. Anda mungkin berpikir entitas seperti kode negara tidak pernah berubah seiring waktu dan akan menjadi kandidat yang baik untuk kunci utama. Tetapi pengalaman pahit jarang terjadi.
INT AUTO_INCREMENT memenuhi kondisi "unik dan tidak berubah dari waktu ke waktu". Karena itu preferensi.
sumber
Saya agak terganggu oleh kurangnya tolok ukur untuk online ini, jadi saya menjalankan tes sendiri.
Perhatikan bahwa saya tidak melakukannya secara teratur, jadi silakan periksa pengaturan dan langkah-langkah saya untuk faktor-faktor yang dapat memengaruhi hasil secara tidak sengaja, dan kirimkan kekhawatiran Anda dalam komentar.
Setup adalah sebagai berikut:
Tabel:
Lalu, saya mengisi 10 juta baris di setiap tabel dengan skrip PHP yang intinya seperti ini:
Untuk
int
tabel, bit($keys[rand(0, 9)])
diganti dengan adilrand(0, 9)
, dan untukvarchar
tabel, saya menggunakan nama negara bagian AS lengkap, tanpa memotong atau memperluasnya hingga 6 karakter.generate_random_string()
menghasilkan string acak 10 karakter.Lalu saya berlari di MySQL:
SET SESSION query_cache_type=0;
jan_int
meja:SELECT count(*) FROM jan_int WHERE myindex = 5;
SELECT BENCHMARK(1000000000, (SELECT count(*) FROM jan_int WHERE myindex = 5));
myindex = 'califo'
untukchar
tabel danmyindex = 'california'
untukvarchar
tabel.Waktu
BENCHMARK
kueri di setiap tabel:Mengenai ukuran tabel & indeks, inilah output dari
show table status from janperformancetest;
(dengan beberapa kolom tidak ditampilkan):Kesimpulan saya adalah bahwa tidak ada perbedaan kinerja untuk use case khusus ini.
sumber
INDEX
bukanPRIMARY KEY
. Saya tidak ingat alasan saya - saya mungkin berasumsiPRIMARY KEY
hanyaINDEX
dengan kendala keunikan. Namun, membaca bagian tentang bagaimana hal-hal disimpan di InnoDB di federico-razzoli.com/primary-key-in-innodb , saya pikir hasil saya masih berlaku untuk kunci utama, dan menjawab pertanyaan tentang perbedaan kinerja pencarian nilai. Juga, komentar Anda menyarankan melihat kinerja algoritma pengurutan , yang tidak berlaku untuk use case yang saya selidiki, yang mencari nilai dalam satu set.Tergantung pada panjangnya .. Jika varchar akan menjadi 20 karakter, dan int adalah 4, maka jika Anda menggunakan int, indeks Anda akan memiliki LIMA kali lebih banyak node per halaman ruang indeks pada disk ... Itu berarti bahwa melintasi indeks akan membutuhkan seperlima dari banyak pembacaan fisik dan / atau logis ..
Jadi, jika kinerja merupakan masalah, diberi kesempatan, selalu gunakan kunci integral yang tidak bermakna (disebut pengganti) untuk tabel Anda, dan untuk Kunci Asing yang mereferensikan baris dalam tabel ini ...
Pada saat yang sama , untuk menjamin konsistensi data, setiap tabel yang penting juga harus memiliki kunci alternatif non-numerik yang berarti, (atau Indeks unik) untuk memastikan bahwa baris duplikat tidak dapat dimasukkan (duplikat berdasarkan atribut tabel yang bermakna).
Untuk penggunaan spesifik yang Anda bicarakan (seperti pencarian negara bagian) itu benar-benar tidak masalah karena ukuran tabelnya sangat kecil .. Secara umum tidak ada dampak pada kinerja dari indeks pada tabel dengan kurang dari beberapa ribu baris. ..
sumber
Benar-benar tidak.
Saya telah melakukan beberapa ... beberapa ... pemeriksaan kinerja antara INT, VARCHAR, dan CHAR.
Meja catatan 10 juta dengan KUNCI UTAMA (unik dan berkerumun) memiliki kecepatan dan kinerja yang sama persis (dan biaya subtree) tidak peduli mana dari tiga yang saya gunakan.
Yang sedang berkata ... gunakan apa pun yang terbaik untuk aplikasi Anda. Jangan khawatir tentang kinerjanya.
sumber
Untuk kode pendek, mungkin tidak ada perbedaan. Ini terutama benar karena tabel yang menyimpan kode-kode ini cenderung sangat kecil (paling banyak dua ribu baris) dan tidak sering berubah (kapan terakhir kali kami menambahkan Negara Bagian AS yang baru).
Untuk tabel yang lebih besar dengan variasi yang lebih luas di antara kunci, ini bisa berbahaya. Pikirkan tentang menggunakan alamat email / nama pengguna dari tabel Pengguna, misalnya. Apa yang terjadi ketika Anda memiliki beberapa juta pengguna dan beberapa dari pengguna tersebut memiliki nama panjang atau alamat email. Sekarang kapan saja Anda perlu bergabung dengan tabel ini menggunakan kunci itu menjadi jauh lebih mahal.
sumber
Adapun Kunci Utama, apa pun yang secara fisik membuat baris unik harus ditentukan sebagai kunci utama.
Untuk referensi sebagai kunci asing, menggunakan integer penambahan otomatis sebagai pengganti adalah ide yang bagus karena dua alasan utama.
- Pertama, biasanya ada lebih sedikit overhead yang terjadi pada join.
- Kedua, jika Anda perlu memperbarui tabel yang berisi varchar unik maka pembaruan harus mengalir ke semua tabel anak dan memperbarui semuanya serta indeks, sedangkan dengan pengganti int, hanya perlu memperbarui tabel master dan itu indeks.
Alasan untuk menggunakan pengganti adalah bahwa Anda mungkin dapat mengizinkan perubahan arti pengganti:
Itu semua tergantung pada apa yang Anda benar-benar perlu khawatirkan dalam struktur Anda dan apa yang paling berarti.
sumber
Kasus umum di mana pengganti
AUTO_INCREMENT
sakit:Pola skema umum adalah pemetaan banyak-ke-banyak :
Performa dari pola ini jauh lebih baik, terutama ketika menggunakan InnoDB:
Mengapa?
id
dan satu indeks.Kasus lain ( negara ):
Terlalu sering, pemula menormalkan country_code menjadi 4-byte
INT
alih - alih menggunakan string 2-byte yang alami, hampir-tidak berubah. Lebih cepat, lebih kecil, lebih sedikit GABUNG, lebih mudah dibaca.sumber
Di HauteLook, kami mengubah banyak tabel kami untuk menggunakan kunci alami. Kami memang mengalami peningkatan kinerja di dunia nyata. Seperti yang Anda sebutkan, banyak pertanyaan kami sekarang menggunakan lebih sedikit gabungan yang membuat kueri lebih berkinerja. Kami bahkan akan menggunakan kunci primer komposit jika masuk akal. Yang sedang berkata, beberapa tabel hanya lebih mudah untuk bekerja dengan jika mereka memiliki kunci pengganti.
Juga, jika Anda membiarkan orang menulis antarmuka ke basis data Anda, kunci pengganti dapat membantu. Pihak ketiga dapat mengandalkan fakta bahwa kunci pengganti hanya akan berubah dalam keadaan yang sangat jarang.
sumber
Saya menghadapi dilema yang sama. Saya membuat DW (skema Constellation) dengan 3 tabel fakta, Kecelakaan di Jalan, Kendaraan dalam Kecelakaan dan Korban dalam Kecelakaan. Data mencakup semua kecelakaan yang tercatat di Inggris dari tahun 1979 hingga 2012, dan tabel 60 dimensi. Secara keseluruhan, sekitar 20 juta catatan.
Tabel fakta hubungan:
RDMS: MySQL 5.6
Secara native, indeks Kecelakaan adalah varchar (angka dan huruf), dengan 15 digit. Saya mencoba untuk tidak memiliki kunci pengganti, begitu indeks kecelakaan tidak akan pernah berubah. Di komputer i7 (8 core), DW menjadi terlalu lambat untuk diminta setelah 12 juta catatan beban tergantung dari dimensinya. Setelah banyak bekerja kembali dan menambahkan kunci pengganti bigint, saya mendapat peningkatan kinerja kecepatan rata-rata 20%. Belum mendapatkan kinerja yang rendah, tetapi coba valid. Saya bekerja di tuning dan clustering MySQL.
sumber
Pertanyaannya adalah tentang MySQL, jadi saya katakan ada perbedaan yang signifikan. Jika itu tentang Oracle (yang menyimpan angka sebagai string - ya, saya tidak percaya pada awalnya) maka tidak banyak perbedaan.
Penyimpanan dalam tabel bukan masalah tetapi memperbarui dan mengacu pada indeks. Kueri yang melibatkan pencarian catatan berdasarkan kunci primernya sering - Anda ingin itu terjadi secepat mungkin karena sering terjadi.
Masalahnya adalah penawaran CPU dengan 4 byte dan 8 byte integer secara alami, dalam silikon . Ini BENAR-BENAR cepat untuk membandingkan dua bilangan bulat - ini terjadi dalam satu atau dua siklus clock.
Sekarang lihat string - terdiri dari banyak karakter (lebih dari satu byte per karakter hari ini). Membandingkan dua string untuk diutamakan tidak dapat dilakukan dalam satu atau dua siklus. Sebaliknya karakter string harus diulang sampai perbedaan ditemukan. Saya yakin ada trik untuk membuatnya lebih cepat di beberapa database tapi itu tidak relevan di sini karena perbandingan int dilakukan secara alami dan kilat cepat dalam silikon oleh CPU.
Aturan umum saya - setiap kunci utama harus merupakan INT peningkatan otomatis terutama di aplikasi OO menggunakan ORM (Hibernate, Datanucleus, apa pun) di mana ada banyak hubungan antara objek - biasanya akan selalu diimplementasikan sebagai FK sederhana dan kemampuan untuk DB untuk menyelesaikannya dengan cepat penting untuk responsif aplikasi Anda.
sumber
Tidak yakin tentang implikasi kinerja, tetapi tampaknya kompromi yang mungkin, setidaknya selama pengembangan, adalah memasukkan kunci "pengganti" integer yang ditambahkan secara otomatis, serta kunci yang Anda inginkan, unik, "alami". Ini akan memberi Anda kesempatan untuk mengevaluasi kinerja, serta masalah-masalah lain yang mungkin terjadi, termasuk perubahan kemampuan kunci alami.
sumber
Seperti biasa, tidak ada jawaban. 'Tergantung!' dan saya tidak bercanda. Pemahaman saya tentang pertanyaan awal adalah kunci pada tabel kecil - seperti Negara (bilangan bulat id atau kode char / varchar) menjadi kunci asing ke tabel berpotensi besar seperti tabel alamat / kontak.
Ada dua skenario di sini ketika Anda ingin data kembali dari DB. Pertama adalah daftar / jenis pencarian kueri di mana Anda ingin membuat daftar semua kontak dengan kode atau nama negara dan negara (id tidak akan membantu dan karenanya perlu pencarian). Yang lainnya adalah skenario get pada kunci utama yang menunjukkan catatan kontak tunggal di mana nama negara, negara perlu ditampilkan.
Untuk mendapatkan yang terakhir, mungkin tidak masalah apa yang menjadi dasar FK karena kita mengumpulkan tabel untuk satu catatan atau beberapa catatan dan pada bacaan utama. Skenario sebelumnya (pencarian atau daftar) dapat dipengaruhi oleh pilihan kami. Karena diharuskan menunjukkan negara (setidaknya kode yang dapat dikenali dan mungkin bahkan pencarian itu sendiri termasuk kode negara), tidak harus bergabung dengan tabel lain melalui kunci pengganti dapat berpotensi (saya hanya berhati-hati di sini karena saya belum benar-benar menguji ini, tetapi tampaknya sangat mungkin) meningkatkan kinerja; terlepas dari kenyataan bahwa itu pasti membantu pencarian.
Karena kode berukuran kecil - tidak lebih dari 3 karakter biasanya untuk negara dan negara, mungkin boleh saja menggunakan kunci alami sebagai kunci asing dalam skenario ini.
Skenario lain di mana kunci bergantung pada nilai varchar yang lebih panjang dan mungkin pada tabel yang lebih besar; kunci pengganti mungkin memiliki keunggulan.
sumber
Izinkan saya untuk mengatakan ya pasti ada perbedaan, dengan mempertimbangkan lingkup kinerja (Definisi di luar kotak):
1- Menggunakan surrogate int lebih cepat dalam aplikasi karena Anda tidak perlu menggunakan ToUpper (), ToLower (), ToUpperInvarient (), atau ToLowerInvarient () dalam kode Anda atau dalam kueri Anda dan 4 fungsi ini memiliki tolok ukur kinerja yang berbeda. Lihat aturan kinerja Microsoft tentang ini. (kinerja aplikasi)
2- Menggunakan pengganti pengganti tidak mengubah kunci dari waktu ke waktu. Bahkan kode negara dapat berubah, lihat Wikipedia bagaimana kode ISO berubah dari waktu ke waktu. Itu akan membutuhkan banyak waktu untuk mengubah kunci utama untuk sub cabang. (kinerja pemeliharaan data)
3 - Tampaknya ada masalah dengan solusi ORM, seperti NHibernate ketika PK / FK tidak int. (kinerja pengembang)
sumber