15%

Tüm Hosting Hizmetlerinde %15 indirim

Becerilerini test et ve herhangi bir hosting planında İndirim kazan

Kodu kullanın:

Skills
Başlayın
08.10.2024

MySQL’de utf8 ve utf8mb4: Eksiksiz Teknik Kılavuz

MySQL’nin utf8 karakter seti adından da anlaşılacağı üzere gerçek bir UTF-8 uygulaması değildir. Karakterleri yalnızca 1 ila 3 bayt kullanarak kodlar; bu da U+FFFF’nin üzerindeki tüm Unicode kod noktalarını, her emojiyi ve tamamlayıcı CJK karakterlerinin önemli bir bölümünü sessizce düşürdüğü veya reddettiği anlamına gelir. utf8mb4, MySQL’nin doğru ve tam UTF-8 uygulamasıdır; karakter başına 1 ila 4 bayt ve eksiksiz Unicode aralığını destekler. 2010 sonrasında oluşturulan herhangi bir üretim veritabanı için utf8mb4, savunulabilir tek seçenektir.

Bu kılavuz, bu ayrımın neden önemli olduğunu, orijinal utf8 tasarımının nerede hatalı olduğunu, güvenli bir şekilde nasıl geçiş yapılacağını ve MySQL’nin sunucu, veritabanı, tablo ve bağlantı düzeyinde nasıl doğru yapılandırılacağını tam olarak açıklamaktadır.

Temel Sorun: MySQL’nin utf8’i Neden Tasarım Gereği Bozuk

UTF-8 kodlama standardı (RFC 3629), her geçerli Unicode kod noktasını temsil etmek için 1 ila 4 bayt kullanan değişken genişlikli bir şema tanımlar — 1,1 milyonun üzerinde olası karakter. MySQL, `utf8` karakter setini 4.1 sürümünde tanıttığında, uygulama kasıtlı olarak karakter başına 3 bayt ile sınırlandırıldı. Bu, bir gözetim değil, bilinçli bir mühendislik kısayoluydu.

O dönemde InnoDB satır biçimi, dizin anahtar öneklerine 767 baytlık bir sınır getiriyordu. 4 baytlık karakterlerin desteklenmesi, `VARCHAR` sütunları için maksimum dizinlenmiş önek uzunluğunu azaltarak dizin uyumluluk sorunları yaratırdı. 3 baytlık sınır, uzun vadeli bir yükümlülüğe dönüşen pragmatik bir geçici çözümdü.

Pratik sonuç: Tamamlayıcı Çok Dilli Düzlem (SMP)‘deki herhangi bir Unicode kod noktası — U+10000 ve üzeri kod noktaları — bir `utf8` sütununda depolanamaz. Bu şunları içerir:

  • Tüm standart emojiler (U+1F600 ve sonrası)
  • Matematiksel alfasayısal semboller (U+1D400–U+1D7FF)
  • Müzik notasyonu sembolleri
  • Linear B, Gotik ve Çivi Yazısı gibi tarihi yazı sistemleri
  • Tamamlayıcı CJK Birleşik İdeograflar (U+20000–U+2A6DF)
  • Son Unicode sürümlerinde eklenen belirli para birimi sembolleri ve teknik operatörler

Bir uygulama `utf8` sütununa 4 baytlık bir karakter eklemeye çalıştığında, MySQL ya bir `Incorrect string value` hatası döndürür ya da `sql_mode` izin verici ise veriyi sessizce keser. Sessiz kesme tartışmasız daha tehlikeli sonuçtur — uygulamanız hiçbir hata almaz, ancak verileriniz bozulur.

utf8mb4: Doğru Uygulama

MySQL, bu eksikliği gidermek amacıyla utf8mb4‘ü özellikle 5.5.3 sürümünde (2010’da yayımlandı) tanıttı. `mb4` son eki “çok baytlı, maksimum 4 bayt” anlamına gelir. `utf8`’ün katı bir üst kümesidir — `utf8`’de temsil edilebilen her karakter, `utf8mb4`’te de aynı şekilde temsil edilebilir. `utf8`’den `utf8mb4`’e geçişte veri kaybı yaşanmaz.

utf8mb4, RFC 3629 UTF-8 standardıyla doğrudan eşleşir. U+0000’dan U+10FFFF’ye kadar olan tam Unicode kod alanını kısıtlama olmaksızın işler.

utf8 ile utf8mb4 Karşılaştırması

Özellikutf8 (MySQL)utf8mb4
Karakter başına bayt1–31–4
Unicode kapsamıYalnızca BMP (U+0000–U+FFFF)Tam (U+0000–U+10FFFF)
Emoji desteğiHayırEvet
Tamamlayıcı CJKHayırEvet
RFC 3629 uyumluHayırEvet
Maksimum dizin öneki (InnoDB, 4KB sayfalar)767 bayt767 bayt (191 karakter)
Maksimum dizin öneki (innodb_large_prefix)3072 bayt3072 bayt (768 karakter)
latin1’e kıyasla depolama yüküASCII için aynıASCII için aynı
Yeni projeler için önerilenHayırEvet
Tanıtıldığı MySQL sürümü4.15.5.3

utf8mb4 İçinde Harmanlama Seçimleri

utf8mb4’ü karakter seti olarak seçmek kararın yalnızca yarısıdır. Harmanlama, dizelerin nasıl karşılaştırıldığını, sıralandığını ve dizinlendiğini belirler. Yanlış harmanlama, hata ayıklaması güç sorgu davranışlarına yol açar.

utf8mb4_unicode_ci

Unicode Harmanlama Algoritması’na (UCA) dayanır. Dile özgü sıralama kurallarını doğru şekilde işler. Daha karmaşık karşılaştırma mantığı nedeniyle `utf8mb4_general_ci`’den biraz daha yavaştır, ancak performans farkı modern donanımda ihmal edilebilir düzeydedir.

utf8mb4_general_ci

UCA’yı tam olarak uygulamayan basitleştirilmiş bir harmanlamadır. 2010’ların başındaki kıyaslamalarda daha hızlıdır, ancak hız avantajı günümüz CPU’larında anlamsızdır. Bazı uç durumları yanlış işler — örneğin, eşdeğer olmaması gereken belirli Almanca karakterleri eşdeğer olarak değerlendirir. Yeni projeler için kullanmaktan kaçının.

utf8mb4_0900_ai_ci

MySQL 8.0+’da mevcuttur. Aksan duyarsız (`ai`) ve büyük/küçük harf duyarsız (`ci`) karşılaştırmayla Unicode 9.0’a dayanır. Bu, MySQL 8.0 ve sonrası için önerilen varsayılandır. `utf8mb4_unicode_ci`’den hem daha hızlı hem de daha doğrudur.

utf8mb4_bin

İkili karşılaştırma — büyük/küçük harf duyarlı, aksan duyarlı, yerel ayara özgü kural yok. Parola karmaları veya büyük/küçük harf duyarlı tanımlayıcılar gibi tam bayt düzeyinde eşleşme gerektiğinde kullanın.

Öneri: MySQL 8.0+’da `utf8mb4_0900_ai_ci` kullanın. MySQL 5.7 ve öncesinde `utf8mb4_unicode_ci` kullanın.

Depolama ve Dizin Etkileri

utf8’den utf8mb4’e geçişte yaygın bir endişe, depolama yüküdür. Pratikte etki minimumdur:

  • ASCII karakterler (U+0000–U+007F) her iki kodlamada da tam olarak 1 bayt kaplar.
  • Latin, Yunan, Kiril, Arapça ve İbranice karakterlerin çoğu her iki kodlamada da 2 bayt kaplar.
  • BMP’deki CJK karakterler her iki kodlamada da 3 bayt kaplar.
  • Yalnızca tamamlayıcı karakterler (emojiler, tamamlayıcı CJK) 4 bayt gerektirir — bunlar zaten utf8’de temsil edilemiyordu.

Asıl dizin endişesi, eski yapılandırmalardaki 767 baytlık InnoDB dizin öneki sınırıdır. utf8mb4 ile karakter başına en fazla 4 bayt durumunda, 191 karakterlik bir `VARCHAR` dizin öneki 767 bayt tavanına ulaşır. `utf8` ile aynı tavan 255 karaktere izin veriyordu. Tam sütun dizinlerine sahip `VARCHAR(255)` sütunlarınız varsa, geçiş sırasında `Specified key was too long` hatalarıyla karşılaşabilirsiniz.

Çözümler:

  • Sınırı 3072 bayta yükseltmek için `innodb_large_prefix = ON` etkinleştirin (MySQL 5.6/5.7).
  • Etkilenen tablolarda `ROW_FORMAT=DYNAMIC` veya `ROW_FORMAT=COMPRESSED` kullanın.
  • MySQL 8.0’da `innodb_large_prefix` varsayılan olarak etkindir ve parametre kaldırılmıştır.
  • Dizin öneklerini kısaltın: `INDEX (column(191))` yerine `INDEX (column(255))`.

Bu, en yaygın geçiş başarısızlık noktasıdır ve temel kılavuzlarda en sık yetersiz belgelenen konudur.

MySQL Veritabanını utf8’den utf8mb4’e Nasıl Geçirilir

Geçiş basittir ancak hassasiyet gerektirir. Herhangi bir katmanı — sunucu, veritabanı, tablo veya bağlantı — atlamak, uygulamanızın sessizce eski kodlamaya geri dönmesine neden olur.

Adım 1: Veritabanını Yedekleyin

Doğrulanmış bir yedek olmadan canlı bir veritabanında karakter kodlamasını asla değiştirmeyin.

“`bash

mysqldump -u username -p –single-transaction –routines –triggers

database_name > database_backup_$(date +%F).sql

“`

`–single-transaction` bayrağı, kilitleme olmaksızın InnoDB tabloları için tutarlı bir anlık görüntü sağlar. Devam etmeden önce yedeği veritabanı sunucusundan ayrı bir konumda saklayın.

Adım 2: MySQL Sunucu Yapılandırmasını Güncelleyin

Dağıtımınıza bağlı olarak `/etc/mysql/my.cnf` veya `/etc/mysql/mysql.conf.d/mysqld.cnf` dosyasını düzenleyin:

“`ini

[client]

default-character-set = utf8mb4

[mysql]

default-character-set = utf8mb4

[mysqld]

character-set-server = utf8mb4

collation-server = utf8mb4_unicode_ci

For MySQL 5.6/5.7 only — remove on MySQL 8.0

innodb_large_prefix = ON

innodb_file_format = Barracuda

innodb_file_per_table = ON

“`

MySQL’yi yeniden başlatın:

“`bash

sudo systemctl restart mysql

“`

Adım 3: Veritabanını Dönüştürün

“`sql

ALTER DATABASE database_name

CHARACTER SET = utf8mb4

COLLATE = utf8mb4_unicode_ci;

“`

Adım 4: Tüm Tabloları Dönüştürün

Her tablo için `ALTER TABLE` ifadeleri oluşturun ve çalıştırın. Bunları büyük şemalarda manuel olarak çalıştırmak hataya açıktır. İfadeleri otomatik olarak oluşturmak için şu sorguyu kullanın:

“`sql

SELECT CONCAT(

'ALTER TABLE `', TABLE_NAME, '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;'

)

FROM information_schema.TABLES

WHERE TABLE_SCHEMA = 'database_name'

AND TABLE_TYPE = 'BASE TABLE';

“`

Oluşturulan her ifadeyi çalıştırın. `CONVERT TO CHARACTER SET` sözdizimi, tablo varsayılanını ve mevcut tüm karakter sütunlarını tek bir işlemde değiştirir.

Adım 5: Dizin Uzunluğu Hatalarını Düzeltin

`Specified key was too long; max key length is 767 bytes` hatasıyla karşılaşırsanız, sorunlu dizini belirleyin:

“`sql

— Change full-column index to prefix index

ALTER TABLE table_name DROP INDEX index_name;

ALTER TABLE table_name ADD INDEX index_name (column_name(191));

“`

Özellikle WordPress veritabanlarında, `wp_options` tablosunun `option_name` sütunu ve `wp_postmeta` tablosunun `meta_key` sütunu bu hatanın yaygın kaynaklarıdır.

Adım 6: Dönüşümü Doğrulayın

“`sql

— Check server-level variables

SHOW VARIABLES LIKE 'character_set%';

SHOW VARIABLES LIKE 'collation%';

— Check a specific table

SHOW CREATE TABLE table_nameG

— Check all columns in a database

SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_SET_NAME, COLLATION_NAME

FROM information_schema.COLUMNS

WHERE TABLE_SCHEMA = 'database_name'

AND DATA_TYPE IN ('char', 'varchar', 'text', 'tinytext', 'mediumtext', 'longtext');

“`

Her `CHARACTER_SET_NAME` değeri `utf8mb4` olarak görünmelidir.

Adım 7: Uygulama Bağlantı Dizelerini Güncelleyin

Uygulamanız yanlış karakter seti kullanarak bağlanıyorsa sunucu ve şema kodlamasının hiçbir önemi yoktur. Bağlantı düzeyindeki kodlama, sunucu varsayılanını geçersiz kılar.

PHP (PDO):

“`php

$dsn = 'mysql:host=localhost;dbname=database_name;charset=utf8mb4';

$pdo = new PDO($dsn, $user, $pass, [

PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"

]);

“`

PHP (MySQLi):

“`php

$mysqli = new mysqli('localhost', $user, $pass, $db);

$mysqli->set_charset('utf8mb4');

“`

Python (mysql-connector-python):

“`python

cnx = mysql.connector.connect(

host='localhost', user=user, password=pass,

database=db, charset='utf8mb4', collation='utf8mb4_unicode_ci'

)

“`

Node.js (mysql2):

“`javascript

const pool = mysql2.createPool({

host: 'localhost', user: user, password: pass,

database: db, charset: 'utf8mb4'

});

“`

Bağlantı karakter setini ayarlamamak, görünürde tamamlanmış bir geçişin ardından emojilerin hâlâ eklenememesinin en yaygın tek nedenidir.

WordPress’e Özgü Dikkat Edilmesi Gerekenler

WordPress, sürüm 4.2’den (Nisan 2015) itibaren varsayılan karakter seti olarak utf8mb4 ile birlikte gelir. Hiç geçirilmemiş eski bir veritabanında WordPress kurulumu çalıştırıyorsanız, `wp-config.php` dosyası hâlâ şunu içeriyor olabilir:

“`php

define('DB_CHARSET', 'utf8');

“`

Bunu şu şekilde değiştirin:

“`php

define('DB_CHARSET', 'utf8mb4');

define('DB_COLLATE', 'utf8mb4_unicode_ci');

“`

WordPress ayrıca çekirdek güncellemeleri sırasında çalışan yerleşik bir yükseltme rutini (`maybe_convert_table_to_utf8mb4()`) içerir. Ancak bu rutin, özellikle eklentiler tarafından oluşturulan tablolar olmak üzere her tabloyu her zaman yakalamaz. Yukarıda açıklanan manuel `ALTER TABLE` yaklaşımını çalıştırmak daha güvenilirdir.

Root erişimine sahip bir VPS Hosting ortamında, bu sürecin tamamını bir kabuk betiğiyle otomatikleştirebilir ve tek seferlik bir cron görevi olarak zamanlayabilirsiniz; bu da zamanlama ve günlük kaydı üzerinde tam kontrol sağlar.

Performans Değerlendirmeleri

utf8mb4’ün utf8’e kıyasla performans etkisi, iş yüklerinin büyük çoğunluğu için ihmal edilebilir düzeydedir:

  • Okuma sorguları: BMP karakterler için ölçülebilir bir fark yoktur. Tamamlayıcı karakterler bir ek bayt I/O gerektirir; bu da arabellek havuzu önbelleğe alması tarafından absorbe edilir.
  • Yazma sorguları: ASCII ve BMP içeriği için aynıdır. Tamamlayıcı karakterler için marjinal olarak daha yüksektir.
  • Dizin işlemleri: Azaltılmış maksimum önek uzunluğu (tam genişlikli dizinler için 255 yerine 191 karakter), uzun `VARCHAR` sütunlarında tam sütun dizinleriniz varsa sorgu planlarını etkileyebilir. Geçiş öncesinde ve sonrasında dizinlerinizi denetleyin.
  • Bellek: MySQL, dize işlemleri için karakter başına maksimum bayt sayısına göre sabit genişlikli arabellekler ayırır. utf8’den (maksimum 3 bayt) utf8mb4’e (maksimum 4 bayt) geçiş, dize yoğun işlemler için bellek içi sıralama arabelleklerine ve geçici tablolara ayrılan belleği yaklaşık %33 oranında artırır. Yeterli RAM’e sahip bir Dedicated Server‘da bu önemsizdir. Bellek kısıtlı paylaşımlı bir ortamda, geçiş sonrasında `sort_buffer_size` ve `tmp_table_size`’ü izleyin.

utf8’in Hâlâ Kabul Edilebilir Olduğu Durumlar

`utf8`’i korumak için meşru nedenler oldukça sınırlıdır:

  • Katı eski uyumluluk: 4 baytlık karakterleri işleyemeyen bakımsız bir ORM veya veritabanı sürücüsü kullanan bir uygulama. Bu, utf8’i süresiz olarak tutmak için bir neden değil, teknik borç sorunudur.
  • Salt okunur arşiv veritabanları: Bir veritabanı hiç yeni yazma almayacaksa ve mevcut veriler tamamlayıcı karakter içermiyorsa, geçiş hiçbir fayda sağlamadan risk ekler.
  • Katı depolama kısıtlamaları: Aşırı uç durumlarda — gömülü sistemler veya ciddi kapasite kısıtlı ortamlar — marjinal depolama farkı önemli olabilir. Bu, herhangi bir standart web barındırma senaryosu için geçerli değildir.

Diğer tüm durumlarda utf8mb4 doğru seçimdir. utf8’in depolama alanı tasarrufu sağladığı argümanı, teknik olarak yalnızca tamamlayıcı karakterler için doğrudur; bunlar zaten utf8’de temsil edilemiyordu. Depolayamadığınız veriler üzerinde alan tasarrufu yapmıyorsunuz.

MySQL utf8mb4 için Doğru Barındırma Ortamını Seçmek

Uygun utf8mb4 yapılandırması, MySQL sunucu yapılandırma dosyasına (`my.cnf`) erişim gerektirir. Bu, sunucu düzeyindeki değişkenleri değiştiremeyeceğiniz çoğu paylaşımlı barındırma ortamını dışarıda bırakır.

MySQL karakter kodlaması, harmanlama, InnoDB ayarları ve bağlantı parametreleri üzerinde tam kontrol için root erişimine sahip bir VPS Hosting planına veya bir Dedicated Server‘a ihtiyacınız vardır. Her ikisi de `/etc/mysql/my.cnf`’e doğrudan erişim, MySQL hizmetini yeniden başlatma imkânı ve utf8mb4 geçiş başarısını etkileyen `innodb_large_prefix`, `ROW_FORMAT` ile diğer parametreleri yapılandırma özgürlüğü sağlar.

Birden fazla veritabanını veya müşteri sitesini yönetiyorsanız, cPanel’li VPS, karakter seti yapılandırması için gereken temel sunucu erişimini korurken veritabanı yönetimi için grafiksel bir arayüz sağlar. Hafif bir panel ile komut satırı esnekliğini tercih eden ekipler için VPS Kontrol Panelleri, farklı operasyonel iş akışlarına uygun çeşitli alternatifler sunar.

Güvenli veri iletimi de gerektiren projeler için veritabanı geçişinizi düzgün yapılandırılmış bir SSL Sertifikası ile eşleştirmek, utf8mb4 ile kodlanmış verilerin yalnızca beklerken değil, aktarım sırasında da korunmasını sağlar.

Teknik Karar Kontrol Listesi

Bu kontrol listesini herhangi bir utf8’den utf8mb4’e geçiş öncesinde ve sonrasında kullanın:

Geçiş öncesi:

  • [ ] Tam `mysqldump` yedeği doğrulandı ve geri yüklenebilir
  • [ ] MySQL sürümü onaylandı (utf8mb4 için 5.5.3+ gerekli)
  • [ ] `innodb_large_prefix` durumu kontrol edildi (MySQL 5.6/5.7’de etkinleştirin)
  • [ ] Tam sütun dizinlerine sahip tüm `VARCHAR(255)` sütunları belirlendi
  • [ ] Uygulama bağlantı karakter seti kodu gözden geçirildi ve güncellendi
  • [ ] Üretim veritabanları için bakım penceresi planlandı

Geçiş sonrası:

  • [ ] `SHOW VARIABLES LIKE 'character_set%'` sunucu düzeyinde `utf8mb4` gösteriyor
  • [ ] `SHOW CREATE TABLE` dönüştürülen tüm tablolarda `utf8mb4` doğruluyor
  • [ ] `information_schema.COLUMNS` sorgusu kalan `utf8` sütunu olmadığını doğruluyor
  • [ ] Bağlantı kodunda uygulama düzeyinde `SET NAMES utf8mb4` veya eşdeğeri onaylandı
  • [ ] Temsili bir tabloda emoji ekleme testi geçildi
  • [ ] Sorgu performansı temeli geçiş öncesi metriklerle karşılaştırıldı
  • [ ] Dizin uzunlukları doğrulandı — uzun dizinlenmiş değerlerin sessiz kesimi yok

SSS

utf8’den utf8mb4’e geçiş veri kaybına neden olur mu?

Hayır. utf8mb4, MySQL’nin utf8’inin katı bir üst kümesidir. utf8 sütununda depolanan her karakter, utf8mb4’te de aynı şekilde temsil edilebilir. Geçiş, mevcut veriler için yıkıcı değildir. Tek risk, tam sütun dizinlerine sahip `VARCHAR(255)` sütunlarındaki dizin uzunluğu hatalarıdır; bunlar dizin önekini kısaltarak çözülmelidir.

Tablolarımı utf8mb4’e dönüştürdükten sonra emojiler neden hâlâ eklenemiyor?

En yaygın neden, uygulama bağlantı karakter setidir. PHP, Python veya Node.js kodunuz `utf8mb4` açıkça belirtmeden bağlanıyorsa, MySQL o oturum için sunucunun `character_set_client` varsayılanını kullanır. Bağlantı yapılandırmanıza `SET NAMES utf8mb4` veya eşdeğer karakter seti parametresini ekleyin.

utf8mb4_unicode_ci ile utf8mb4_0900_ai_ci arasındaki fark nedir?

`utf8mb4_unicode_ci` Unicode 4.0 harmanlama kurallarına dayanır ve MySQL 5.7 için standart seçimdir. `utf8mb4_0900_ai_ci` Unicode 9.0’a dayanır, MySQL 8.0’da varsayılandır ve hem daha hızlı hem de dilbilimsel açıdan daha doğrudur. Yeni projeler için MySQL 8.0+’da `utf8mb4_0900_ai_ci` kullanın.

utf8mb4’e geçiş veritabanı depolama boyutumu önemli ölçüde artırır mı?

Pratikte hayır. ASCII ve BMP karakterlerin çoğu her iki kodlamada da aynı sayıda bayt kullanır. Yalnızca tamamlayıcı karakterler (emojiler, tamamlayıcı CJK) 4 bayt kullanır — bunlar zaten utf8’de temsil edilemiyordu. Dize yoğun işlemler için sıralama arabelleklerinin bellek yükü yaklaşık %33 artar, ancak bu herhangi bir modern sunucuda ihmal edilebilir düzeydedir.

Paylaşımlı barındırmada utf8mb4 yapılandırabilir miyim?

Kısmen. SQL `ALTER` ifadelerini kullanarak karakter setini veritabanı ve tablo düzeyinde ayarlayabilir, uygulamanızın bağlantı dizesinde karakter setini belirtebilirsiniz. Ancak paylaşımlı barındırmada `my.cnf` dosyasını değiştiremez veya MySQL’yi yeniden başlatamazsınız. Sunucu düzeyindeki varsayılanlar değişmeden kalır; bu da barındırma paneli aracılığıyla oluşturulan yeni veritabanlarının utf8 varsayılanına dönebileceği anlamına gelir. Tam utf8mb4 yapılandırması, root erişimine sahip bir VPS veya dedicated server gerektirir.

15%

Tüm Hosting Hizmetlerinde %15 indirim

Becerilerini test et ve herhangi bir hosting planında İndirim kazan

Kodu kullanın:

Skills
Başlayın