MySQL - varchar uzunluğu ve performansı


Yanıtlar:


31

Bu çok yaygın bir "sınav / mülakat sorusu" dur. Elimden geldiğince iyi cevap vereceğim:

InnoDB ve MyISAM (dinamik / kompakt) için standart satır biçimlerinde a VARCHAR(50)ve a VARCHAR(255), dize metnini aynı şekilde saklar - uzunluk için 1 bayt ve karakter başına 1 ile 4 bayt arasında (kodlamaya ve saklanan gerçek karakter).

Yanlış hatırlamıyorsam Aslında, birinin bir benzeri değişim şey için bir onaltılık editörü ile veri sözlüğü değiştirerek hatırlama VARCHAR(50)bir içine VARCHAR(100)(bir tablo yeniden gerektirdiğini, normalde) dinamik olarak yapılabilir, böylece. Ve bu mümkün, çünkü gerçek veriler bu değişiklikten etkilenmedi.

Bu doğru değildir VARCHAR(256), çünkü o zaman uzunluk için 2 bayt (en azından) her zaman gereklidir.

Yani bu her zaman yapmamız gerektiği anlamına gelir, VARCHAR(255)değil mi? Hayır . Bunun birkaç nedeni var.

InnoDB dinamik bir şekilde bir varchar depolayabilirken, bu diğer motorlar için geçerli değildir. MyISAM sabit satır boyutu biçimine sahiptir ve BELLEK tabloları her zaman boyut olarak sabittir. Bu diğer motorları önemsemeli miyiz? Evet, çünkü doğrudan kullanmasak bile, BELLEK tabloları ara sonuçlar (bellekte geçici tablolar) için çok yaygın olarak kullanılır ve sonuçlar önceden bilinmediği için, tablo maksimum boyutta oluşturulmalıdır mümkün - VARCHAR(255)bu bizim tipimizse. Boşa harcanan alanı düşünebiliyorsanız, MySQL'in 'utf8' charsetkodlamasını kullanıyorsanız , MEMORY satır başına + 3 * 255 bayt uzunluğu için 2 bayt ayıracaktır.(InnoDB'de yalnızca birkaç bayt alabilecek değerler için). Bu, 1 VARCHAR için sadece 1 milyon masada neredeyse 1GB. Bu sadece gereksiz bellek stresine neden olmakla kalmaz, aynı zamanda disk üzerinde gerçekleştirilecek eylemleri de kışkırtabilir ve potansiyel olarak binlerce kez yavaşlatabilir. Bunların hepsi, tanımlanmış veri türünün zayıf bir seçiminden dolayı (içerikten bağımsız olarak).

InnoDB için de bazı sonuçları var. Dizin boyutu 3072 bayt ve tek sütun dizinleriyle, 767 bayt * ile sınırlıdır. Bu nedenle, birVARCHAR(255) alanı tam olarak dizine ekleyemeyeceksiniz (utf8 veya başka bir değişken uzunluk kodlaması kullandığınız varsayılarak).

Buna ek olarak, InnoDB için maksimum satır içi satır boyutu yarım sayfadır (yaklaşık 8000 bayt) ve BLOB veya varchar gibi değişken uzunluklu alanlar , yarım sayfaya sığmazlarsa sayfa dışında saklanabilir . Bunun performansta göz ardı edilemeyecek bazı sonuçları vardır (bazen iyi, bazen kötü, kullanıma bağlı olarak). Bu, COMPACT ve DİNAMİK formatları arasında biraz tuhaflığa neden oldu. Bkz. Örneğin: hata 1118: satır boyutu çok büyük. utf8 innodb

Son fakat en az değil, @ ypercube bana hatırlattığı gibi, uzunluk da bayt depolarken, VARCHAR(255)tanım karakterlerde olduğu için, uzunluğu 1 bayttan fazla kullanmanız gerekebilir . Örneğin REPEAT('ñ', 255)utf8 içinde 2 ^ 255 bayttan fazla olduğundan, uzunluğunu depolamak için 1 bayttan fazla gerekir:

mysql> SELECT LENGTH(REPEAT('ñ', 255));
+---------------------------+
| LENGTH(REPEAT('ñ', 255))  |
+---------------------------+
|                       510 |
+---------------------------+
1 row in set (0.02 sec)

mysql> SELECT CHAR_LENGTH(REPEAT('ñ', 255));
+--------------------------------+
| CHAR_LENGTH(REPEAT('ñ', 255))  |
+--------------------------------+
|                            255 |
+--------------------------------+
1 row in set (0.00 sec)

Bu nedenle genel tavsiye, mümkün olan en küçük türü kullanmaktır , çünkü aksi takdirde performans veya yönetim sorunları yaratabilir. Tam uzunluğu bilmeseniz bile, A VARCHAR(100)daha iyidir VARCHAR(255)(a VARCHAR(20)daha iyi olsa da). Muhafazakar olmaya çalışın çünkü tablo çok büyük değilse tanımı daha sonra istediğiniz zaman değiştirebilirsiniz.

Güncelleme: Değişken uzunlukta dizelerin popülaritesi, örneğin emoji kullanımı nedeniyle, Oracle bu durumlar için gelişmiş performans için baskı yapıyor. En son MySQL sürümlerinde (5.6, 5.7), InnoDB hem içsel hem de açık geçici tablolar için varsayılan motor olarak ayarlanmıştır, bu da değişken uzunluklu alanların artık birinci sınıf vatandaş olduğu anlamına gelir. Bu, çok kısıtlı karakter uzunluklarına sahip olmak için daha az neden olabileceği anlamına gelir (ancak bunlar hala mevcuttur).

(*) İkinci Güncelleme : large_prefix_index artık en son MySQL sürümlerinde (8.0) varsayılan olarak etkindir, ancak bu eski sürümler için veya gecikme innodb dosya / satır biçimlerini (dinamik veya sıkıştırılmış dışında) kullanıyorsanız hala geçerlidir, ancak şimdi varsayılan olarak, tek sütun dizinleri bu 3072 bayta kadar olabilir.


küçük güncelleme: MySQL-8.0.13 +, varchars için verimli depolama alanına sahip geçici tablolar için varsayılan olarak TempTable kullanır .
danblack

0

1'e karşı 2 bayt önekini unutun VARCHARs.

  • Performansı çok küçük bir miktarda etkiler.
  • Açık kuralın söylediklerinden daha sık "2" dir.

255 ile ilgili soru birçok kez sorulmuş ve cevaplanmıştır.

  • Çok uzun süre VARCHARsbaşarısızlığa yol açabilir CREATE TABLE.
  • Temp tabloları, tablolara dönüşebilir MEMORY, VARCHARsdönüştü VARCHAR. Bu, örneğin, VARCHAR(255) CHARACTER SET utf8mb41020 baytlık sabit bir uzunluk isteyen anlamına gelir . (Bu başarısız olur ve MyISAM'ı kullanmak için dejenere olur.)

Alt satır: 255 (veya 256) körü körüne kullanmayın; şema için mantıklı olanı yapın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.