MariaDB'de veri tipi seçerken üç soruya cevap verirsiniz: değer hangi aralıkta olacak, kesin mi yaklaşık mı saklanmalı ve diskte ne kadar yer kaplayacak. Tamsayılar için TINYINT'ten BIGINT'e kadar 1 ile 8 bayt arası tipler, kesin ondalık değerler için DECIMAL, metin için CHAR, VARCHAR ve TEXT, zaman için DATE, DATETIME ve TIMESTAMP kullanılır.
Bu yazı resmî belgelerdeki Data Types bölümüne, özellikle Data Type Storage Requirements, Numeric Data Type Overview, INT, DECIMAL, VARCHAR, TIMESTAMP, NULL Values ve AUTO_INCREMENT sayfalarına dayanır. Tabloyu nasıl oluşturacağınız veritabanı ve tablo oluşturma yazısında, tarih fonksiyonları tarih ve saat fonksiyonları yazısında ayrıca anlatılıyor; serinin haritası için MariaDB öğrenme rehberine bakabilirsiniz.
Tipin önemi: aralık, kesinlik ve strict kip
Bir sütuna tipinin alamayacağı bir değer yazmaya çalıştığınızda ne olacağını sql_mode belirler. Belgeye göre varsayılan sql_mode değeri STRICT_TRANS_TABLES, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER ve NO_ENGINE_SUBSTITUTION bileşenlerinden oluşur. STRICT_TRANS_TABLES açıkken aralık dışı bir değer hata üretir ve satır eklenmez. Strict kip kapalıysa MariaDB değeri sığabilecek en yakın değere çeker ve yalnızca bir uyarı verir; uyarıyı görmezseniz verinin sessizce değiştiğini fark etmeyebilirsiniz.
Numeric Data Type Overview sayfasındaki örnek bu farkı gösteriyor. Aynı tabloya 257 yazıldığında strict kip kapalıyken TINYINT sütunu 127'ye, TINYINT UNSIGNED sütunu 255'e kırpılıyor:
CREATE TABLE ranges (i1 TINYINT, i2 SMALLINT, i3 TINYINT UNSIGNED);
INSERT INTO ranges VALUES (257,257,257);
Query OK, 1 row affected, 2 warnings (0.00 sec)
SHOW WARNINGS;
+---------+------+---------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------+
| Warning | 1264 | Out of range value for column 'i1' at row 1 |
| Warning | 1264 | Out of range value for column 'i3' at row 1 |
+---------+------+---------------------------------------------+
2 rows in set (0.00 sec)
SELECT * FROM ranges;
+------+------+------+
| i1 | i2 | i3 |
+------+------+------+
| 127 | 257 | 255 |
+------+------+------+Strict kip açıkken aynı INSERT şu hatayla reddedilir ve tablo boş kalır: ERROR 1264 (22003): Out of range value for column 'i1' at row 1. Sunucunuzun kipini SELECT @@sql_mode; ile kontrol etmeniz, bu yazıdaki davranışların hangisinin sizde geçerli olduğunu anlamanın en kısa yoludur.
Tamsayı tipleri

Tamsayılar beş boyutta gelir. Belgedeki aralıklar ve depolama gereksinimleri şöyledir:
| Tip | Bayt | İşaretli aralık | UNSIGNED aralık |
|---|---|---|---|
| TINYINT | 1 | -128 ile 127 | 0 ile 255 |
| SMALLINT | 2 | -32768 ile 32767 | 0 ile 65535 |
| MEDIUMINT | 3 | -8388608 ile 8388607 | 0 ile 16777215 |
| INT | 4 | -2147483648 ile 2147483647 | 0 ile 4294967295 |
| BIGINT | 8 | -9223372036854775808 ile 9223372036854775807 | 0 ile 18446744073709551615 |
SIGNED varsayılandır ve tipin bir bölümü işarete ayrılır. UNSIGNED yazdığınızda negatif değerler yasaklanır ve pozitif aralık iki katına çıkar. ZEROFILL ise değeri, parantez içindeki M basamak sayısına kadar soldan sıfırla doldurur ve sütunu otomatik olarak UNSIGNED yapar. Belge, ZEROFILL'in ifadelerde ve UNION içinde yok sayıldığını, standart dışı bir MySQL ve MariaDB eklentisi olduğunu da belirtir. Bir not: MEDIUMINT diskte 3 bayt tutar ama bellekte, örneğin InnoDB buffer pool içinde 4 bayt kaplar.
INT sayfasındaki örnek, strict kip açıkken üç farklı tanımın aynı değerlere nasıl tepki verdiğini gösterir. -10, UNSIGNED ve ZEROFILL sütunlarına yazılamaz; 2147483648 ise işaretli INT için bir fazladır:
CREATE TABLE ints (a INT,b INT UNSIGNED,c INT ZEROFILL);
INSERT INTO ints VALUES (-10,-10,-10);
ERROR 1264 (22003): Out of range value for column 'b' at row 1
INSERT INTO ints VALUES (-10,10,-10);
ERROR 1264 (22003): Out of range value for column 'c' at row 1
INSERT INTO ints VALUES (-10,10,10);
INSERT INTO ints VALUES (2147483648,2147483648,2147483648);
ERROR 1264 (22003): Out of range value for column 'a' at row 1
INSERT INTO ints VALUES (2147483647,2147483648,2147483648);
SELECT * FROM ints;
+------------+------------+------------+
| a | b | c |
+------------+------------+------------+
| -10 | 10 | 0000000010 |
| 2147483647 | 2147483648 | 2147483648 |
+------------+------------+------------+Çıktıdaki 0000000010, ZEROFILL'in etkisidir; değerin kendisi hâlâ 10'dur. INT(11) gibi yazımlardaki sayı aralığı değiştirmez, yalnızca ZEROFILL ile birlikte gösterim genişliği anlamına gelir.
BOOLEAN aslında TINYINT(1)
BOOL ve BOOLEAN, belgeye göre TINYINT(1) ile eş anlamlıdır. Sıfır yanlış, sıfırdan farklı her değer doğru kabul edilir; TRUE ve FALSE sözcükleri de 1 ve 0 için takma addır. Bu yüzden bir BOOLEAN sütuna 5 gibi bir değer yazılabilir. SHOW CREATE TABLE çıktısında sütun tinyint(1) olarak görünür:
CREATE TABLE boolean_example (
example BOOLEAN
);
SHOW CREATE TABLE boolean_example\G
*************************** 1. row ***************************
Table: boolean_example
Create Table: CREATE TABLE `boolean_example` (
`example` tinyint(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1Kesin ve yaklaşık ondalık sayılar
DECIMAL(M,D) belgede "kesin" (exact) sabit noktalı sayı olarak tanımlanır. M toplam basamak sayısı, D ondalık kısmın basamak sayısıdır. M en fazla 65, D en fazla 38 olabilir; ikisi de verilmezse M için 10, D için 0 kullanılır. Ondalık nokta ve eksi işareti M'ye dahil edilmez. D sıfırsa eklenen değer en yakın tamsayıya yuvarlanır. Toplama, çıkarma, çarpma ve bölme işlemleri 65 basamak hassasiyetle yapılır. Depolamada tam ve ondalık kısımlar ayrı tutulur; her dokuz basamak 4 bayt kaplar, kalan basamaklar için 1 ile 4 bayt arası ek alan kullanılır.
FLOAT (tek duyarlıklı, yaklaşık 7 ondalık basamak doğruluğunda) ve DOUBLE (çift duyarlıklı, 8 bayt) ise yaklaşık değer saklar. Floating-point Accuracy sayfası, bu tiplerin eşitlik operatörüyle karşılaştırılmasının güvenli olmadığını şu örnekle gösterir:
CREATE TABLE fpn (id INT, f1 FLOAT, f2 DOUBLE, f3 DECIMAL (10,3));
INSERT INTO fpn VALUES (1,2,2,2),(2,0.1,0.1,0.1);
SELECT * FROM fpn WHERE f1*f1 = f2*f2;
+------+------+------+-------+
| id | f1 | f2 | f3 |
+------+------+------+-------+
| 1 | 2 | 2 | 2.000 |
+------+------+------+-------+
SELECT f1*f1, f2*f2, f3*f3 FROM fpn;
+----------------------+----------------------+----------+
| f1*f1 | f2*f2 | f3*f3 |
+----------------------+----------------------+----------+
| 4 | 4 | 4.000000 |
| 0.010000000298023226 | 0.010000000000000002 | 0.010000 |
+----------------------+----------------------+----------+İkinci satırda 0,1 değerinin karesi FLOAT ve DOUBLE için farklı küçük sapmalar taşıdığından eşleşme bulunamıyor, DECIMAL ise tam 0,010000 veriyor. Belge ayrıca MariaDB'deki tüm hesapların çift duyarlıkla yapıldığını, bu yüzden FLOAT kullanmanın beklenmedik sonuçlar doğurabileceğini not eder. Fiyat, bakiye ve miktar gibi tam olması gereken değerlerde bu nedenle DECIMAL tercih edilir.
Metin tipleri: CHAR, VARCHAR, TEXT ve ENUM

CHAR(M) sabit uzunlukludur: değer kaydedilirken sağdan boşlukla M karaktere tamamlanır, okunurken sondaki boşluklar atılır. M 0 ile 255 arasındadır, verilmezse 1 kabul edilir. VARCHAR(M) değişken uzunlukludur; M karakter cinsinden en fazla uzunluktur ve 0 ile 65.532 arasında olabilir. Gerçek üst sınır satır boyutu limitine ve karakter setine bağlıdır: belgedeki örneğe göre karakter başına üç bayta kadar kullanan utf8 ile bir VARCHAR en fazla 21.844 karakter tanımlanabilir. MariaDB VARCHAR değerlerindeki sondaki boşlukları silmez.
Depolama farkını belge tek baytlık bir karakter seti için şöyle özetler. VARCHAR her değere bir uzunluk baytı ekler (değerler 255 baytı aşabiliyorsa iki bayt):
| Değer | CHAR(2) olarak | Bayt | VARCHAR(2) olarak | Bayt |
|---|---|---|---|---|
| '' | ' ' | 2 | '' | 1 |
| '1' | '1 ' | 2 | '1' | 2 |
| '12' | '12' | 2 | '12' | 3 |
TEXT en fazla 65.535 karakterlik uzun metin içindir ve iki baytlık uzunluk öneki taşır; daha büyük metinler için MEDIUMTEXT ve LONGTEXT vardır. Belge VARCHAR ile TEXT arasındaki pratik farkları da sayar: VARCHAR tamamen indekslenebilir, TEXT ise yalnızca belirli bir uzunluğa kadar indekslenebilir. Ayrıca geçici tablo kullanan bir SELECT içinde TEXT veya BLOB bulunması geçici tablonun diske yazılmasına yol açar.
ENUM('a','b',...) yalnızca listedeki değerlerden birini kabul eder ve içeride tamsayı olarak saklanır; 255 değere kadar 1, 65.535 değere kadar 2 bayt kaplar. Strict kip kapalıyken geçersiz bir değer yazılırsa uyarıyla birlikte indeksi 0 olan özel bir boş dize eklenir. DEFAULT verilmemişse varsayılan, sütun NULL kabul ediyorsa NULL, etmiyorsa listedeki ilk değerdir. Belge, sıralamanın tanım sırasına göre yapıldığını hatırlatır ve sayıları ENUM içinde saklamamayı önerir, çünkü tırnaksız yazılan sayı değer yerine indeks olarak yorumlanabilir.
Bunlara ek olarak MariaDB'de 16 bayt tutan UUID ve INET6 tipleri vardır. UUID tipi belgeye göre MariaDB 10.7'den beri kullanılabilir ve değeri RFC4122'deki metin biçiminde döndürür.
Tarih ve saat tipleri
| Tip | Bayt | Desteklenen aralık |
|---|---|---|
| DATE | 3 | 1000-01-01 ile 9999-12-31 |
| TIME | 3 | Saat ve süre değerleri |
| DATETIME | 8 | 1000-01-01 00:00:00.000000 ile 9999-12-31 23:59:59.999999 |
| TIMESTAMP | 4 | 1970-01-01 00:00:01 UTC ile 2106-02-07 06:28:15 UTC (MariaDB 11.5 ve sonrası) |
| YEAR | 1 | Yıl değeri |
DATETIME ve TIMESTAMP 0 ile 6 arasında mikrosaniye hassasiyeti alabilir; parantez verilmezse 0 kullanılır. Hassasiyet ek alan gerektirir: 1 ve 2 basamak için 1, 3 ve 4 için 2, 5 ve 6 için 3 bayt.
İki tip arasındaki temel fark saat dilimidir. TIMESTAMP değeri yazılırken oturumun saat diliminden UTC'ye çevrilir, okunurken yeniden oturumun saat dilimine döndürülür; değerle birlikte bir saat dilimi kimliği saklanmaz. DATETIME ise yazdığınız değeri olduğu gibi tutar. Belgeye göre TIMESTAMP'ın üst sınırı MariaDB 11.5'ten önce 2038-01-19 03:14:07 UTC idi; 11.5 ve sonrasında 2106'ya uzatıldı.
TIMESTAMP'ın otomatik değer davranışı explicit_defaults_for_timestamp değişkenine bağlıdır. Bu değişken kapalıyken (belgeye göre MariaDB 10.10'a kadar varsayılan buydu) tablodaki ilk TIMESTAMP sütunu kendiliğinden DEFAULT CURRENT_TIMESTAMP ve ON UPDATE CURRENT_TIMESTAMP özelliklerini alır. Sürümden bağımsız ve okunaklı bir şema için bu davranışı açıkça yazmak en güvenli yoldur:
CREATE TABLE siparis (
id INT AUTO_INCREMENT PRIMARY KEY,
olusturma TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
guncelleme TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);Bu tanımda olusturma yalnızca ekleme anında doldurulur, çünkü ON UPDATE yazılmamıştır; guncelleme ise her UPDATE'te yenilenir. Belge, DATE ve DATETIME için '0000-00-00' sıfır tarihinin NO_ZERO_DATE kipi açık değilse kabul edildiğini, sıfır tarih içeren ifadelerin çoğu durumda NULL verdiğini de not eder.
NULL: boş değil, bilinmeyen
NULL bilinmeyen değeri temsil eder; boş dize ya da sıfır değildir. Belgenin en çok altını çizdiği nokta karşılaştırmalardır: =, <, > gibi operatörlerle NULL karşılaştırması ne doğru ne yanlış, yine NULL verir. Bunun için IS NULL, IS NOT NULL ve NULL güvenli eşitlik operatörü <=> kullanılır:
SELECT NULL = NULL;
+-------------+
| NULL = NULL |
+-------------+
| NULL |
+-------------+
SELECT 99 <=> NULL, NULL <=> NULL;
+-------------+---------------+
| 99 <=> NULL | NULL <=> NULL |
+-------------+---------------+
| 0 | 1 |
+-------------+---------------+Sıralamada NULL en küçük değer gibi davranır; artan sıralamada başta, azalan sıralamada sonda görünür. DISTINCT ve GROUP BY için tüm NULL değerler eşit sayılır. Depolama tarafında InnoDB'nin COMPACT, DYNAMIC ve COMPRESSED satır biçimleri, NULL olabilen alanlar için satır başlığında bit ayırır ve NULL değer için veri alanında yer kullanmaz.
AUTO_INCREMENT ve SERIAL
AUTO_INCREMENT sütunu, değer verilmediğinde ya da NULL veya DEFAULT verildiğinde sayacın bir sonraki değerini alır; NO_AUTO_VALUE_ON_ZERO kipi açık değilse 0 da aynı etkiyi yapar. Sayaç varsayılan olarak 1'den başlar. Her tabloda yalnızca bir tane olabilir ve bir anahtar olmalıdır; InnoDB'de çok sütunlu anahtarın ilk sütunu olması gerekir. Belgedeki örnek:
CREATE TABLE animals (
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO animals (name) VALUES
('dog'),('cat'),('penguin'),
('fox'),('whale'),('ostrich');
SELECT * FROM animals;
+----+---------+
| id | name |
+----+---------+
| 1 | dog |
| 2 | cat |
| 3 | penguin |
| 4 | fox |
| 5 | whale |
| 6 | ostrich |
+----+---------+Değerlerde boşluk oluşması normaldir: silinen satırların numaraları yeniden kullanılmaz, REPLACE eski satırı silip yeni numara üretir, InnoDB'de geri alınan bir transaction'ın ayırdığı değer de kaybolur. Belge bu yüzden bu değerlerin kronolojik sıralama için kullanılabileceğini ama kesintisiz bir numara dizisi olarak görülmemesi gerektiğini söyler. Son üretilen değeri oturum bazında LAST_INSERT_ID() verir. SERIAL ise BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE için bir kısaltmadır.
Sık yapılan hatalar

- Para değerlerini FLOAT veya DOUBLE ile saklamak. Yaklaşık tipler eşitlik karşılaştırmalarında sürpriz yapar; tutarlar için
DECIMAL(M,D)kullanın. - INT(11) yazınca 11 basamaklı sayı sığacağını sanmak. Parantezdeki sayı aralığı değiştirmez; aralık tipin kendisine bağlıdır.
- Strict kipi kapatıp uyarıları okumamak. Aralık dışı değerler kırpılarak eklenir; uygulamanız hatalı veriyi fark etmez.
- WHERE sutun = NULL yazmak. Sonuç her zaman
NULLolduğundan hiçbir satır gelmez;IS NULLkullanın. - Uzun vadeli tarihleri eski sürümde TIMESTAMP ile tutmak. 11.5 öncesinde üst sınır 2038'dir; geniş aralık gerekiyorsa
DATETIMEdüşünün. - AUTO_INCREMENT değerlerinin kesintisiz olmasını beklemek. Silme, geri alma ve
REPLACEboşluk bırakır; fatura numarası gibi ardışık değerler için ayrı bir mekanizma gerekir.
Sık Sorulan Sorular
VARCHAR(255) ile VARCHAR(256) arasında fark var mı?
Belgeye göre VARCHAR, değer 255 baytı aşmıyorsa bir, aşabiliyorsa iki uzunluk baytı kullanır. Sınır karakter değil bayt cinsindendir; çok baytlı karakter setlerinde bu eşik daha az karaktere denk gelir.
Türkçe metin için hangi karakter setini seçmeliyim?
Belge, utf8'in karakter başına bir ile üç, utf8mb4'ün bir ile dört bayt kullandığını belirtir. Seçim ve collation ayarları karakter seti ve collation yazısında ayrıntılı anlatılıyor.
JSON için ayrı bir tip var mı?
Evet, belgede bir JSON veri tipi tanımlıdır ve varsayılan olarak utf8mb4 karakter setini kullanır. Sorgulama fonksiyonları JSON fonksiyonları yazısının konusu.
Bir sütunun tipini sonradan değiştirebilir miyim?
Evet, ALTER TABLE ... MODIFY veya CHANGE ile. Var olan veri yeni tipe dönüştürülür, bu yüzden önce yedek almanız önerilir. Ayrıntılar ALTER TABLE yazısında.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: MariaDB öğrenme rehberi · tablo oluşturma · INSERT, UPDATE ve DELETE · tarih ve saat fonksiyonları · utf8mb4 ve collation · JSON fonksiyonları