Neden MySQL kullanmamaliyim? Yerine ne kullanabilirim? [PostgreSQL]

@aib MySQL’e “dandik” diyip duruyor, neden? Hakkaten kullanmamali miyim? Yerine ne kullanabilirim?

4 Beğeni

Not: MySQL ile son temasim ve son buyuk basagrim 10 sene kadar once idi. Bir kismi simdiye kadar duzelmis olabilir ama ayni kalmissa sasirmam; o noktada “yeni” sayilmazdi.

MySQL, database’lerin temeli olarak bilinen ACID prensiplerini “olursa iyi olur” diye alan bir sistem. Cogunun patladigi ornegi asagilarda okuyabilirsiniz.

SQL standardini da “benzesek fena olmaz” diye kullanan bir sistem. En buyuk sapmalari da asagida olacak…

“Ogrenmek icin” kullanmakta bir sakinca yok fakat PostgreSQL’e tercih edilecegi bir durum dusunemiyorum. Kurulum kolayligi? Cesitlilik?

Production’da filan kullanirsaniz “tablo [az milyon] row’da patlamaya basladi, query yapamiyoruz, kolon bile silemiyoruz” diye gelmeyin. “Facebook kullaniyormus” diye de gelmeyin; Facebook’a gidin.

PostgreSQL. Bu arada su dokumentasyon baska database kullanirken bile ise yariyor.

Tek program icin data tutuyorsan SQLite bolgesine yakinsin. “Database” demeye bin sahit istemekle beraber kendi alaninda cok iyi oldugu icin bahsedeyim dedim.

Veya SQL kullanmamayi dusundun mu? Dilinin serialization kutuphaneleri cok daha kolay olabilir.


2010’da sozluge yazdigim bir entry var. Oldugu gibi atiyorum:

bas agrilari:

  1. boolean kolon turu yoktur. “bool” kolon tur ismi tinyint(1)'e alias’lidir. insanlari true/false yerine 1/0 insert etmeye itmesi bile yeter.

  2. otomatik artan (bkz: auto-increment) kolon turu yoktur.

  3. enum kolonlarina enum’da olmayan bir deger insert etmenize izin verir ve yaptiginizda bambaska bir deger (’’) insert eder.

  4. enum kolonlarinda enum‘da olmayan bir deger (’’) saklamaniza izin verir.

  5. ansi standart quote’lari opsiyoneldir ve default kapali gelir. export tool’lari, ansi standart quote’lari kullanan script’ler uretemez.

  6. drop table, truncate table; rollback edilebilmeyi birakin, o anki transaction’i commit eder.

  7. constraint check’leri defer edilemez. fk'li iki rowu birbirine bagladiktan sonra silmeye calisip eglenebilirsiniz. (ipucu: on delete)

  8. yanlis date/datetime expression’larini 0000-00-00 [00:00:00]'a cevirir.

  9. saniyenin altinda granularitede tarih/saat tutamaz.

  10. her turlu index operasyonu icin butun tabloyu, gecici bir tabloya kopyalayip geri almak sureti ile bastan yaratir. (gecici tablo limiti asarsa disk tablosuna duser)

  11. || operatorunu or operatoru zanneder.

  12. text, binary data ve hatta integer'lar icin degisik bir suru kolon tipleri vardir. text mi yoksa mediumtext mi kullanmaliyim diye dusunup durursunuz.

  13. regexp destegi match’ten ibarettir. (capture yok, replace yok)

  14. union kullanan view'larda index propogasyonu yapamaz, once view'i gecici bir tabloda materyalize edip, sonra filtrelemek sureti ile sonuc dondurur. (gecici tablo limiti asarsa disk tablosuna duser)

  15. query planner’i limit'li query’leri pek iyi optimize edemez, row'lari order'a gore getirip filtre uygulamanin cok daha hizli olacagi durumlari es gecip filtrelemeyi once yapabilir. (http://www.mysqlperformanceblog.com/2010/03/18/when-the-subselect-runs-faster/)

  16. query’lerde tablo basina tek index kullanmayi cok sever. explain ciktisinda bile “kullanilan index” yazar. insanlarda "where clause’unda ne kadar kolon kullaniyorsan hepsini ayni sirada birlestiren bir multi-kolon index yaratmalisin" gibi yanlis dusuncelerin dogmasina neden olur.

  17. null olamayan ve default degeri olmayan kolonlara kafasina gore default deger verir.

  18. ansi standart comment sekansini ("–") tanimaz.

  19. query planner’i, 3-5 id donduren subselect uzerinden diger kolonlari secen bir query kullandiginizda, her seyin gecici bir tabloya atilmasina; full tabloyu saniyenin altinda scan eden aletin disk access yapacagim diye dakikalarca debelenmesine neden olabilir. “select * from tablo where id in (select id from tablo where …)” gibi bir query’i elle optimize etmek zorunda kalirsiniz: ic query’i calistirir, sonuclari alir, aralarina virgul koyup where in ()'e atarsiniz. virgulleri tek tek elle koydugunuz halde bile orijinal query’den daha hizli (milisaniye vs. dakikalar) sonuc alirsiniz.

  20. yine subselect’lerle ilgili ama yukaridakinden bagimsiz olarak, 0 sonuc donduren bir ic query’e ragmen toplam query’nin 10 saniye surdugu gorulmustur. tekrarlayalim; ic query: 0 result, dis query: haliyle 0 result, running time: 10.0xx saniye. bu durum ic query’nin dondurdugu row sayisina gore degisir: 0, 1, 3 ve 99 row donduren ic query’i kullanip ayni sayida row donduren query’lerin 10.0xx saniye; 2, 4, 5, 150 ve 384 row dondurenlerin ise milisaniyeler aldigi gozlemlenmistir. hepsi son derece supheli bir sekilde ~10 saniye suren yavas query’lerden hic data kullanmayan 0/0 row’luk olani debug modu acik calistirilip bi yandan da source koddan takip edildiginde ise edinilen sonuc sudur: innodb, 0’ar byte’lik data paketleri ‘yollayan’ bir “sending data” sonsuz loop’una girmistir. 10 saniye ise kendisine verilen timeout suresidir.

  21. tek kolonlu bos innodb tablosuna iki thread’den insert yaparsaniz deadlock olabilirler!! (http://bugs.mysql.com/bug.php?id=51140#c282323)
    ya abi, yok… ben bosuna ugrasiyorum. bu… yani… yazi yazma yetenegimi kaybettim. sunun uzerine ne diyebilirim ki? ne desem fayda edecek ki?

[eklemiycem baska bisiy, yeter be]

  1. “select *, count(*) […]” gibi bir query’e izin verirken “select count(*), * […]” gibi bir query’e izin vermez.

  2. gruplu query’lerde gruplanmamis kolonlari secmenize izin verir: “select a, b […] group by a” (gerci ne yalan soyliyim, elle query yaparken “select * […] group by a” diyip ful sema arti her kolondan birer ornek gormeyi seviyorum.)

  3. gruplu query’lerde gruplanmamis kolonlari secerseniz butun degerlerine tek tek bakip herhangi birini dondurmek icin table scan’e duser. (ama ender durumlarda index kullanabileceginden supheleniyorum)

  4. where analizi “(x is null or x is not null)” gibi bir clause’un her zaman true olacagini bilemez (ve index fail’leriyle beraber (#16) muhtemelen table scan’e dusurur)

  5. where clause’lari icin schema analizi yapamaz; not null kolona “(x is null)” gibi bir kosul verdiginizde dahi tum tabloyu tarar. (aslinda index taramasi lazim, ama bakiniz yukarisi, #16.)

  6. tablolari sadece nested loop ile join edebilir! (soldaki her row icin: sagdaki karsiligi bul) oha oha oha - ben de niye denormalizasyon hastasi diyordum insanlar.

  7. advisory lock vardir ama baglanti basina bir tane alinabilir. (ikincisi alinirsa ilki otomatikmen unlock edilir)

  8. paralelizasyonu felakettir; tutup 32 cpu’lu makinaya kurarsaniz 28’i ile protein katlayabileceginizi fark edersiniz.

  9. explain sadece select’lerde calisir.

siyasiler ve daha neler neler: http://sql-info.de/mysql/gotchas.html

http://dev.mysql.com/doc/refman/5.1/en/server-sql-mode.html adresinde dokumente edilen (5.1’i kendi versiyonunuzla degistirebilirsiniz) opsiyonlarin bir kismiyla yukaridaki basagrilarinin bir kismini duzeltebilir, veya manyaksaniz daha fazlasini bulabilirsiniz.

ahahahahah
ahahahahaa
ahahaaahahahaa
utf-8 desteklemiyormus. gidin bakin siz de gulun: http://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8.html (edit: 5.5’te gelmis)

2 Beğeni

Veritabanları gereksizdir. Büyük şirketler bütün bilgilerini asdf.csv diye bir dosya açıp, araya virgül koya koya oraya yazarlar.

@aib hocanın sinirlerini bozduğuma göre gidebilirim…

Ah evet cok iyi dedin. Gordugum database kullanan cogu sistem, bir text dosyasi, bir CSV, bir JSON veya en azindan SQLite kullansa, daha hizli bir surede, daha az basagrisiyla ve daha hizli calisacak sekilde yazilabilirdi.

Ozellikle burada, login datasi filan tutan insanlara dict pickle etseydin dememek icin kendimi zor tutuyorum, yeri geldiginde diyorum. Tabi ki yine “ogrenmek icin” kullanilmasina karsi degilim.

“Rule of thumb”: En az bir foreign key constraint’iniz olmayacaksa SQL buyuk ihtimalle overkill yani gereksiz.

4 Beğeni

Bu benim de hiç düşünmediğim bir şeydi, öğrendiğim iyi oldu.

Kendi sorusunu kendi cevaplayan aib:

5 Beğeni

Ben:

3 Beğeni