Veritabanında Enum türünde bir sütun oluşturmak için aşağıdaki söz dizimini kullanırız;
CREATE TABLE shirts (
name VARCHAR(40),
size ENUM('x-small', 'small', 'medium', 'large', 'x-large')
);
SQLEnum kullanımı veri bütünlüğü ve sınırlamalar sağlamakta çok kullanışlıdır. Belirli değer setlerini sınırlamasının yanı sıra indekslere dayalı bir depolama sağladığı için performans açısından da avantaj sağlayabilir. Ancak yanlış kullanımlar performans sorunlarına, beklenmeyen sonuçlara ya da ölçeklenebilirliğe zarar verebilir.
Neden Enum kullanmamalıyım?
Yanlış kullanımla ortaya çıkacak sorunlardan bazıları; veri karışıklığı olabilir. Veri karışıklığı; sayısal değer kullanımında Enum indeksleriyle karışabilir. Örneğin ‘1’ değeri Enum’ın ilk değerine karşılık gelir. Ancak siz 3. sırada ‘1’ değerini tanımladıysanız ve başka bir sırada da 1 değerini tanımladıysanız; bu Enum’a erişimde sorunlarla karşılaşabilir; muhtemelen hatalı bir veriyle karşılaşırsınız.
Değişim Sorunu
Bir başka sorunsa değişime ayak uydurma tarafında ortaya çıkıyor. Günümüz dünyasında herşey hızlı değişmekte. Ve bu değişikliklere Enum kullanarak ayak uydurmaya çalışmak beraberinde büyük zorluklar getirebilir. Yukarıda verdiğimiz örneği genişletip bir xx-large eklemek istediğimizi düşünelim. Bu durumda MySQL’in tüm tabloyu yeniden oluşturacak. Hele bir de x-small’ı kaldırırsanız; x-small değerini kontrol etmek için her kaydı inceleyecektir.
Örnek kullanım açısından; her ülke bir kıtaya ait olmak zorundadır. Bu yüzden bir ülkenin hangi kıtaya ait olduğuna dair veriyi Enum formatında tutabiliriz. Ancak yakın zamanda değişecek ya da değiştirilebilecek verileri bir referans tablosunda* tutmak çok daha sağlıklı olacaktır.
-- ENUM sütununa yeni değer eklemek
ALTER TABLE shirts MODIFY COLUMN size ENUM('x-small', 'small', 'medium', 'large', 'x-large', 'new-size')
-- Referans tablosunda yeni değer eklemek
INSERT INTO shirt_sizes (name) VALUES ('new-size')
/*
Enum kullandığımız sütun için yeni değer eklerken ALTER TABLE kullanıyoruz. ALTER TABLE işleminde 3 farklı algoritma kullanılabilir.
Bunlar;
1. COPY
2. INPLACE
3. INSTANT
*/
SQLAlter Table Algoritmalarıyla ilgili daha detaylı bilgi için: 13.1.9 ALTER TABLE Statement
Listeleme Sorunu
Listeleme problemi başlı başına acı verici olacaktır. DISTINCT değeri ile Enum olan sütunu sorgulayabilirsiniz. Ancak bu olası tüm değerler yerine sadece kullanılan ve tabloda mevcut olan değerleri döndürecektir. Tanımlanmış tüm değerlere erişmek istediğiniz zaman INFORMATION_SCHEMA üzerinden sorgulama yapmanız gerekmektedir. Bunun yerine bir referans tablosu kullanmanız maliyet açısından çok daha faydalı olacaktır.
Bir referans tablosu kullanmak performans açısından size çok sağlıklı gelmiyor mu? Enum Fields VS Varchar VS Int + Joined table: What is Faster? makalesini incelemenizde fayda olacağını düşünüyorum.
Yeniden Kullanım Sorunu
Yeniden kullanım açısından da sorunlara yol açabilir. Enum değerlerini başka bir tabloda kullanmak bir yana; başka bir veritabanına geçmeniz gerektiğinde Enum veri türü kaynaklı olarak başınız derde girebilir; neden mi? Enum değeri standart SQL değildir ve tüm SQL veritabanları Enum değerini desteklemeyebilir. Örneğin PostgreSQL 8.3 sürümünden önce Enum’ı desteklemiyordu. IDBM DB2, AFAIK, IBM Informix Dynamic Server ve Oracle’da Enum’ı desteklemeyen veritabanları arasında sayılabilir.
Enum neden var?
Enum her zaman kötü değildir. Yakın zamanda değişmesi mümkün olmayan verileri saklama açısından oldukça başarılı bir iş çıkarmaktadır. Örneğin iskambil kağıtlarını düşünelim. Kırmızı ve Siyah renklere sahip; Kupa, Maça, Karo ve Sinek değerlerine sahibiz. Bu durumda aşağıdaki şekilde bir tablo oluşturabiliriz;
CREATE TABLE iskambil_kartlari (
siyah_mi TINYINT(1) ZEROFILL,
tur ENUM('kupa', 'maça', 'karo', 'sinek', '')
);
SQLBu iyi bir yaklaşım olacaktır. En sonda eklenen boş değer ise Joker’i temsil ediyor. Bundan daha iyi başka bir yaklaşım ise kıta tanımlamaları olabilir.
Ayrıca 2’den fazla ve 20’den az öğe içerecek şekilde kullanımlar da sağlıklı olacaktır. Öğe sayısı 20’den sonra hantal hale gelmekle birlikte yönetimi ve üzerinde çalışılması oldukça zorlu olacaktır.
Enum kullanırken ne yapmaktan kaçınmalısın?
Numaraları Enum olarak vermekten kaçınmanız yapacağınız ilk iş olmalı. Çünkü Enum veri türü; verileri belirlendikleri sırayla değil, indekse göre sıralar. Yukarıda da belirttiğim gibi eğer ‘1’ değerine sahip bir öğe ve 1 değerine sahip başka bir öğe kullanırsanız ortalık biraz karışacaktır. Aşağıdaki kod anlamanız açısından fayda sağlayacaktır.
CREATE TABLE test (foobar ENUM('0', '1', '2'));
mysql> INSERT INTO test VALUES (1), ('1');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM test;
+--------+
| foobar |
+--------+
| 0 |
| 1 |
+--------+
2 rows in set (0.01 sec)
Bir başka öneriyse strict mode kullanmanız. Bu sayede Enum sütunu için geçersiz bir değer eklemeye çalışırsanız en azından bir hata alabilirsiniz. Strict mode kullanmadığınız durumlarda ise sadece uyarı verilir ve yalnızca boş bir dize (0 indeksine) olarak ayarlanır.
Peki ne yapacağız bu Enum ile?
Geliştirme ve bakım açısından size mantıklı gelen çözüm ile ilerlemeniz en sağlıklı olandır. MySQL’in Enum veri türü yerine referans tablolarını kullanmak birçok açıdan avantaj sağlayacaktır. Ancak yine de Enum kullanmanızın doğru ve sağlıklı seçenek olduğu durumlarla da karşılaşacaksınız.