MySQL İlişkisel Veritabanı Yönetim Sistemi (MySQL Relational Database Management System) (RDBMS) geniş bir yelpazede veri tiplerini destekler. Tablonuzun sütunu için seçtiğiniz veri tipi önemlidir çünkü bu, verilerinizin MySQL’de nasıl saklanacağına karar verir. Bir verinin farklı veri tipleri kullanılarak saklanması mümkündür. Ancak hangi veri tipinin kullanılası en uygundur ya da iyi sonucu verir?
En uygun olanı nedir?
Ben, en az depolama alanı kaplayanını ve/veya arama veya veri çekme açısından en hızlı olanını en uygun olarak tanımlarım. MySQL kullanma kılavuzu şöyle der: “En uygun depolama için, her zaman en hassas (uygun) veri tipini kullanmaya çalışmalısınız. Örneğin, tam sayı (integer) tipindeki bir sütun 1 ile 99999 arasındaki değerler için kullanılacaksa MEDIUMINT UNSIGNED kullanmak en iyisidir. Verilen değerler için diğer tüm tipler arasından bu tip, en az miktarda depolama alanı kullanır.”
MySQL veri tipleri
MySQL çeşitli kategorilerde birçok vri tipini destekler: Nümerik tipler, tarih ve zaman tipleri ve dizge/karakter (string/character) tipleri. Veri tipleri, spesifik bir işlevi yerine getirmek için oluşturulmuştur. Bazı tipler küçük miktarlardaki yazıyı saklamak için uygun iken diğer bazı tipler büyük miktardaki yazıları, diğer bazı tipler tarihleri ve diğer bazı tipler sayıları… Tablolarınızı oluşturmak, her sütuda veri depolamak için en uygun hangi veri tipini kullanacağınızı anlamanın en iyi yoludur. Bu geniş ve karmaşık bir alandır. Bu yüzden bazı kullanışlık örnek ve ipuçları ile kısa bir bakış açısı sunmayı umuyorum.
Yanlış veri tipi kullanım örneği
TEXT veri tipi, en fazla 65,535 byte (yaklaşık olarak aynı sayıdaki karaktere eş değer) uzunluktaki dizgeleri depolamak için tasarlanmıştır. Bu nedenle nispeten büyük dizgeleri (string’leri) depolamak için tasarlanmıştır diyebiliriz. VARCHAR veri tipinde ise bu değer, MySQL 5.0.3 sürümünden önce 0 ile 255 byte/karakterdir. Bu sebeple bu veri tipinin de nispeten küçük dizgeleri depolamak için tasarlandığı söylenebilir. Depolama, TEXT veri tipindeki sütun için veri uzunluğu artı 2 byte gerektirirken VARCHAR sütunu için veri uzunluğu artı bir byte gerektirir. Bakıldığı zaman bu çok büyük bir tasarruf olarak görülmeyebilir ama milyonlarca kaydın bulunduğu bir tablonuz olduğunda bu küçük yardımın ne kadar önemli olduğu anlaşılacaktır.
Bir sayıyı depolarken teorik olarak TEXT veya VARCHAR veri tipleri kullanılabilir ve istediğiniz gibi ekleme, düzenleme, silme ve verileriniz arasında arama yapabilirsiniz. Bununla birlikte sayıları MySQL’in numerik veri tiplerinden birisinde depolamanız daha iyidir. Sayıları uygun veri tiplerinde depolamak demek onun daha az depolama alanı kullanması ve tablonuzda aramaların daha hızlı yapılabilmesi demektir.
Örnekler ve Uygulamalar
Sayılar (Integers)
Sayılar genellikle MySQL’in numerik veri tiplerinden birisi kullanılarak depolanır. Numerik veri tipleri, muhtemelen sizlerin de sıklıkla kullandığı, TINYINT, SMALLINT, MEDIUMINT, INT ve DECIMAL’dir. Bu numerik veri tiplerinden ilk dördü minumum ve maksimum değerler arasındaki tam sayıları (tam sayılara negatifleri de dâhildir) depolamak için kullanılır. Örneğin TINYINT sütunu -128 ile 127 arasındaki depolayabilir. INT -2147483648 ile 2147483647 arasındaki sayıları depolayabilir. TINYINT sütununun depolama gereksinimi 1 byte iken INT sütunun 4 byte’tır. SMALLINT ve MEDIUMINT bu değerler arasındaki sayıları da kapsar. Bu sebeple, eğer bir sütunun 1 ile 99 arasında bir sayı tutacağını biliyorsanız TINYINT veri tipi kullanmalısınız ki bu durumda daha az depolama alanına ihtiyaç olur.
Tamsayı (integer) alanları UNSIGNED olarak seçin.
Numerik veri tiplerinin UNSIGNED özelliğini seçerek numerik değerlerini genişletebilirsiniz.Bu özellik seçildiğinde negatif değerlere izin verilmez ve böylece TINYINT sütunu 0 ile 255 arasındaki tam sayıları depolayabilir. INT sütunu ise 0 ile 4294967295 arasındaki tam sayıları depolayabilir. Bunun anlamı, negatif değerlerine ihtiyacınız olmayan büyük tam sayıları daha küçük bir depolama gereksinimi ile bir veri tipinde kullanabilirsiniz.
MySQL’de parasal değerleri kaydetme
Parasal değerleri tabi ki dizge (string) olarak (örneğin VARCHAR tipinde) depolayabilirsiniz ancak en uygun veri tipi DECIMAL’dir. Bu numerik veri tipi numerik veri değerlerini tamı tamına (örneğin ondalık kısmı ile bir sayıyı) kaydetmede kullanır. MySQL kullanım kılavuzu DECIMAL’i şu şekilde açıklar: “… örneğin parasal veriler gibi hassasiyeti korumanın önemli olduğu değerleri saklamak için kullanılır.“
DECIMAL bir sütunda, duyarlılık ve ölçeği örneğin DECIMAL(5,2) şeklinde belirlediğinizde MySQL bunu şu şekilde açıklıyor:
“Bu örnekte, 5 hassasiyet ve 2 ise ölçektir. Hassasiyet saklanan değerdeki anlamlı basamak sayısını, ölçek ise ondalık noktadan sonraki basamak sayısını temsil eder. Eğer ölçek 0 olursa ondalık ve nümerik değerler herhangi bir ondalık nokta veya kesirli kısım içeremezler.“
Dizgeler (Strings)
Dizgeler (karakter ve yazılar vs.) birçok farklı veri tipi kullanılarak depolanabilir. Karşımıza çıkan ana tipler ise CHAR, VARCHAR ve TEXT’tir. İlk olarak gördüğümüz, TEXT veri tipi büyük boyutlu dizgeleri (65,535 byte) depolamada kullanılır. Bu sebeple, bu veri tipi, büyük miktarlardaki yazıları depolamada kullanılmalıdır.
Peki kısa dizgeler depolanırken hangi veri tipi kullanılacak? CHAR veya VARCHAR mı kullanmalıyız? Her iki veri tipi de 0 ile 255 byte veri saklayabilirken MySQL’in 5.0.3 sürümünden itibaren VARCHAR’ın kapasitesi 65,535 byte’a yükseltilmiştir. Bu yüzden nasıl bir seçim yapacağız? Her veri tipinin avantajları ve dezavantajları vardır.
CHAR
Bir CHAR sütunun uzunluğu, siz tabloyu oluşturduğunuzda belirlediğiniz uzunluğa kadar ayarlanmıştır ve veri kaydettiğinizde belirlenen uzunluğa kadar verinin sağına boşluk atar. Böylece eğer siz bir sütunun değerini CHAR(255) olarak tanımlamışsanız, sadece birkaç karakter ekleseniz bile, depolama gereksinimi 255 byte olacaktır. Ne var ki, CHAR sütunun hız avantajı vardır. Çünkü sabit uzuznluktadır ve MySQL CHAR sütununda diğer çeşitli uzunluktaki sütunlara göre daha hızlı arama yapabilir. Ancak artan performanstan faydalanmak için bütün tablo aynı uzunlukta olmalıdır. Eğer tablonuzda VARCHAR ve TEXT gibi diğer veri tipleri varsa, satırlar değişken uzunluğa gelir ve hızda hiçbir artış olmaz.
VARCHAR
VARCHAR sütunundaki değerler, değişken uzunluktaki dizgelerdir. CHAR’ın aksine VARCHAR değerleri artı bir byte önek eklenerek depolanırlar. Bu yüzden, yukarıdaki örnekte olduğu gibi, VARCHAR(255) şeklinde bir sütun tanımladığınızda ve sadece beş karakterlik bir veri eklediğinizde depolama gereksinimi sadece altı byte olacaktır. Bu sebeple dizgelerinizin (string’lerinizin) değişken uzunlukta olması durumunda VARCHAR veri tipi daha az depolama alanına gereksinim duyacaktır.
CHAR – VARCHAR karşılaştırması
Eğer tablonuz sadece sabit uzunluktaki değerler içeriyorsa CHAR kullanmak MySQL’de daha hızlı arama yapmada avantaj sağlar. Eğer sütunlardan herhangi bir tanesi değişken uzunlukta ise VARCHAR kullanmak daha az depolama gereksinimine ihtiyaç duyduğu için daha avantajlı olacaktır.
Tarihler
Bir tarih değerini dizge (string) olarak kaydedebilmenize rağmen MySQL’in tarihleri daha uygun şekilde depolamasına imkân veren yolları vardır.
Unix Timestamp
Tarihleri kusursuz bir biçimde depolamanın yollarından bir tanesi Unix Timestamp veri tipini kullanmaktır. Bir Unix zaman damgası (Timestamp), Unix’in kurulduğu 1 Ocak 1970 tarihinden bu yana geçen saniyeleri temsilen 10 basamaklı bir sayıdır. Bu sayı 10 byte depolama alanı gerektiren bir CHAR sütununda tutulabilir. Ancak bunun için daha uygun olan veri tipi nümerik tiplerden sadece 4 byte depolama alanı gerektiren INT(UNSIGNED) veri tipidir.
Eğer date() fonksiyonu ile birlikte PHP kullanıyorsanız Unix zaman damgası daha kullanışlıdır. Çünkü PHP zamanı seçtiğiniz formata çok kolay bir şekilde dönüştürebilir ve siz saniye sayısı ekleyerek ya da çıkararak tarih hesaplayabilirsiniz. Örneğin, 86400 (24*60*60) sayısı 24 saate eşittir.
Unix zaman damgasını kullanmanın dezavantajlarından bir tanesi de bu formattaki bir veriyi insanların veritabanlarından doğrudan okumada yaşadıkları zorluktur. Mesela 1262986313 sayısının hangi zamana denk geldiğini söyleyebilir misiniz? Diğer dezavantaj ise 10 basamaktan kaynaklanmaktadır. Çünkü Unix zaman damgası 9999999999 değerine ulaştığı 19 Ocak 2038 günü saat 03:14:07’de sorunlara neden olabilir. Çünkü tahmin edileceği üzere bu tarihten sonra Unix zaman damgası 11 basamaklı olacaktır.
DATETIME
Son zamanlara kadar tarihleri MySQL’de depolamak için Unix zaman damgası kullanıyordum ancak şimdilerde DATETIME veri tipini kullanmaya başladım2. DATETIME 2010-01-08 15:00:00 gibi hem tarihleri hem zamanları depolayabilmek için özel olarak tasarlanmıştır.
DATETIME veri tipini kullanmanın dezavantajlarından bir tanesi Unix zaman damgasının iki katı yani 8 byte depolama alanı gerektirmektedir. Ama DATETIME kullanmanın Unix zaman damgası kullanmaya nazaran daha ağır bastığına inanıyorum3.
İlk olarak DATETIME kullanılarak veritabanında depolanan tarihler, insanlar tarafından okunabilir durumdadır. phpMyAdmin’i açtığınızda verinizin daha okunabilir olduğunu ve verinizin ne anlama geldiğini siz de çok rahat görürsünüz.
İkinci olarak MySQL, DATETIME formatı ile çalışmak için yerleşik fonksiyonların hepsini barındırır. Tarih ekleyip çıkarabilirsiniz, iki tarih arasındaki farkı hesaplayabilirsiniz, tarihi istediğiniz formata dönüştürüp çıktılayabilirsiniz ve sadece MySQL kullanarak PHP’nin ek fonksiyonları olmadan çok daha fazlasını yapabilirsiniz.
Ve son olarak, DATETIME sütununuzu Unix zaman damgasına çevirmek isterseniz MySQL’in bunu yapmak için yerleşik fonksiyonları da vardır.
Ayrıca MySQL sadece yılı, zamanı ve bununla ilgili birçok tipi depolayabilir.
Diğer
ENUM
ENUM sütunları, sadece belirli türden veri içerebilir değerleri tanımlamak için etkili bir yol sağlar.Bu yüzden, örneğin, sütununuz sadece ‘var 1’, ‘var 2’, ‘var 3’ değerlerini içeriyorsa ENUM veri tipini kullanabilirsiniz. Bu yöntem, bu tür veriler için, MySQL’de verileri dizge (string) olarak depolamaktan çok daha uygundur. Örneğin, kullanıcının aktif ya da pasif olup olmadığını denetlerken VARCHAR olarak ‘aktif’ ya da ‘pasif’ şeklinde depolamak yerine ENUM kullanmak daha uygundur.
Sonuç olarak…
Veri, sütunlarda birçok farklı veri tipleri kullanılarak depolanabilir. Verilerinizi depolamak (saklamak) için uygun olan genellikle bir veri tipi vardır. En uygun veri tipini kullanmak, veri depolama ve hız açısından fayda sağlar.
Bu yazı, Developer Websites sitesinde yer alan “How to Choose the Optimal MySQL Data Type” adlı yazının genel olarak Türkçe’ye çevirisidir. Bu sebeple dikkat etmeye çalışmama rağmen yazı, çeviri kokabilir.