吐槽時間到——劍指大家都喜愛的高人氣關(guān)系數(shù)據(jù)庫
MySQL易于安裝、速度相對出色而且包含豐富的功能選項(xiàng)。如果單憑這些還不足以吸引你,它同時也是開源運(yùn)動當(dāng)中最具代表性的旗艦性項(xiàng)目之一——它的成功故事告訴我們,一家以開源為立足根基的企業(yè)同樣能夠獲得巨大成功。
令人不禁怒吼WTF的八大MySQL常見問題
然而,相信每一位使用過MySQL的朋友都曾經(jīng)出于某種理由將自己的怒拳揮向屏幕——哐!!!雖然平心而論,我們不可能建立起一套能夠存儲成千上萬條互聯(lián)網(wǎng)信息的技術(shù)體系,又要求其從來不出任何差錯。但是,一旦差錯出現(xiàn),一股恨意總會涌上大家的心頭——也包括我自己。
在今天的文章中,我們整理出關(guān)于這套開源關(guān)系數(shù)據(jù)庫的八大漏洞,而這些正是經(jīng)常導(dǎo)致用戶神經(jīng)錯亂的元兇所在。其中一部分并不限于MySQL本身,它們會在各類關(guān)系類數(shù)據(jù)庫當(dāng)中頻頻出現(xiàn)。但如果不把關(guān)系類數(shù)據(jù)庫跟MySQL進(jìn)行明確劃分,那么我們將永遠(yuǎn)生活在上世紀(jì)九十年代。所謂不破不立,正視問題也就是解決問題的第一步(當(dāng)然,大家也可以選擇存在時間還不太長的其它新型數(shù)據(jù)庫,但它們同樣也是問題纏身——必然的)。
深層缺陷與特有問題
任何一套規(guī)模龐大的軟件包都會存在漏洞。不過從深層角度來看,MySQL的各類漏洞已經(jīng)形成了自己的一套風(fēng)格與體系。在選擇MySQL的同時,大家必須馬上集中注意力——因?yàn)樵谶@里,NULL的作用在不同情況下會發(fā)生改變,而外鍵約束的效果亦往往與我們的期望不符……就連自動遞增都會鬧出各種意料之外的麻煩。
MySQL當(dāng)中存在著幾十個這樣的小問題,而且它們時不時就要跳出來折騰一番。有鑒于此,一部分用戶專門整理出了清晰的錯誤清單。但MySQL至少擁有一套出色的漏洞報(bào)告系統(tǒng),因此我們可以了解到那些自己尚未意識到或者遇到過的潛在問題。遇上錯誤別激動,其他人也在經(jīng)歷著同樣的命運(yùn)。
關(guān)系表欠缺靈活性
表帶來了紀(jì)律性,紀(jì)律性絕不是壞事——但強(qiáng)迫程序員們不得不按照僵化的預(yù)定義列打理數(shù)據(jù)就很令人頭痛了。NoSQL之所以能夠在短時間內(nèi)迅速風(fēng)靡全球,就是因?yàn)樗鼮槌绦騿T提供充分的靈活性,允許他們隨時對數(shù)據(jù)模型加以強(qiáng)化。如果需要為聯(lián)系地址添加一行新內(nèi)容,大家可以在NoSQL當(dāng)中輕松通過插入來實(shí)現(xiàn)。而如果各位打算添加任何一個完整的新數(shù)據(jù)塊,NoSQL模型也能夠順利加以接納,而不會強(qiáng)行要求用戶以預(yù)設(shè)方式進(jìn)行提交。
想象一下,我們可能剛剛創(chuàng)建出一套以整數(shù)形式存儲郵政編碼的表。它的效率很高,而且所采用的強(qiáng)制規(guī)則也完全可以接受。接下來,有人發(fā)送了一條包含連字符的九位郵政編碼、或者收到一封包含有加拿大地址郵編的信件,這時我們該怎么辦?
這時,相信大家和我一樣,聽見了夢想破壞的聲音……老板希望網(wǎng)站能在幾小時內(nèi)順利上線,因此我們根本沒時間對整套解決方案進(jìn)行重構(gòu)。那么程序員該怎么做?也許需要利用一些小技巧將加拿大的郵政編碼轉(zhuǎn)化為Base64數(shù)字,再將其轉(zhuǎn)換回Base10?又或者利用一條專門的轉(zhuǎn)義碼設(shè)置輔助表,從而聲明真正的郵政編碼其實(shí)被保存在其它位置?誰知道呢。我們有幾十種解決問題的辦法,但這些小訣竅總會帶來其它潛在麻煩。不過沒轍,時間緊迫,網(wǎng)站不能按時上線、我們是要丟飯碗的。
MySQL的關(guān)聯(lián)規(guī)則原本希望能讓每位用戶都抱有誠實(shí)謹(jǐn)慎的好心態(tài),但實(shí)際上卻讓我們不得不通過小聰明來規(guī)避這種約束。
JOIN
曾幾何時,將數(shù)據(jù)拆分成多個表代表著計(jì)算機(jī)科學(xué)領(lǐng)域的一大卓越進(jìn)步。這不僅意味著我們能夠顯著降低表的大小,同時也為用戶帶來良好的簡化效果。但在JOIN語句當(dāng)中,這種紀(jì)律性與收益開始要求我們?yōu)橹冻龃鷥r。
在SQL當(dāng)中,還沒有哪部分組件能像JOIN這樣逼迫開發(fā)人員建立一系列復(fù)雜語句,并承受由此帶來的混亂與絕望。在此之后,存儲引擎還需要找到最優(yōu)方式來高效解壓這些JOIN語句??偠灾?,這相當(dāng)于開發(fā)人員被迫建立起復(fù)雜的查詢表述,而數(shù)據(jù)庫則被迫對其進(jìn)行梳理。
正因?yàn)槿绱?,很多追求速度表現(xiàn)的開發(fā)人員干脆放棄了這一進(jìn)步,轉(zhuǎn)而采用非規(guī)范化方式處理。相較于對條目進(jìn)行拆分,大家直接將數(shù)據(jù)對象匯總成一個巨大的表,而這就規(guī)避了其復(fù)雜性。如此一來,運(yùn)行速度不僅更快,服務(wù)器也不至于(頻繁)出現(xiàn)內(nèi)存溢出狀況。
如今磁盤存儲空間已經(jīng)相當(dāng)廉價。市場上已經(jīng)出現(xiàn)了單磁盤8 TB產(chǎn)品,而容量更大的方案也即將亮相。所以相信在不久的將來,我們將徹底告別該當(dāng)活剮的JOIN。
混亂的fork
沒錯,穩(wěn)定且受到良好支持的MySQL fork能夠刺激市場競爭并帶來更多后備選項(xiàng),但其同時也會引發(fā)混亂與困惑。更糟糕的是MariaDB這款fork的出現(xiàn)——作為Monty Widenius負(fù)責(zé)運(yùn)營的項(xiàng)目,其背后的支持人員同時也參與了MySQL的開發(fā)。那么MariaDB到底值不值得我們采用并信賴?或者說我們更應(yīng)該選擇MySQL?我們是否應(yīng)當(dāng)堅(jiān)持使用使用由該數(shù)據(jù)庫原始開發(fā)者們所提供的中心代碼?或者轉(zhuǎn)而投向技術(shù)水平更高且技術(shù)成果更酷的新陣營的懷抱?
除此之外,我們又該如何解讀關(guān)于兼容性方面的信息?一方面,開發(fā)團(tuán)隊(duì)告訴我們MariaDB與MySQL在相當(dāng)程度上能夠?qū)崿F(xiàn)互換。但在另一方面,可以肯定的是二者之間仍然存在差異——為什么非要腳踏兩條船并為此苦苦掙扎?也許雙方的性能表現(xiàn)接近,而我們的查詢也能夠在其中以同樣的方式起效?但實(shí)際情況可能并非如此——或者隨著兩個項(xiàng)目的持續(xù)發(fā)展而出現(xiàn)背道而馳的局面。
存儲引擎讓人暈頭轉(zhuǎn)向
MySQL并不屬于真正的單一數(shù)據(jù)庫;它實(shí)際是打著統(tǒng)一的旗號,暗藏眾多更為具體的細(xì)節(jié)內(nèi)容。在發(fā)展初期,它使用的引擎名為MyISAM,其速度出色但在一致性方面有所欠缺。但這不算什么大事,因?yàn)橛袝r候我們確實(shí)需要更理想的速度水平,而且能夠承受一致性方面的妥協(xié)。
但在人們需要更多方案時,InnoDB攜完整的事務(wù)支持能力登場了。但它的表現(xiàn)仍然無法令人完全滿意。時至今日,我們面對著20種存儲引擎選項(xiàng)——其數(shù)量遠(yuǎn)遠(yuǎn)超出了驅(qū)動數(shù)據(jù)庫管理實(shí)例的實(shí)際需要。誠然,能夠在無需重寫SQL的前提下在不同引擎之間往來切換有時候確實(shí)是件好事,但由此帶來的麻煩同樣不容忽視。我到底該為自己的表選擇MyISAM還是InnoDB?又或者最好是以CSV格式進(jìn)行數(shù)據(jù)導(dǎo)出?
利益動機(jī)
作為一款成功的開源產(chǎn)品,MySQL仍然代表著一整套由專業(yè)開發(fā)人員構(gòu)建、且需要據(jù)此獲得回報(bào)的業(yè)務(wù)體系。盡管大部分用戶能夠通過開源許可免費(fèi)享受由此帶來的出色功能,但該公司顯然需要賺取充足的利潤才能持續(xù)、健康、穩(wěn)定地保持發(fā)展。這就意味著,以“社區(qū)版”旗號免費(fèi)發(fā)布的版本肯定要與面向企業(yè)的完整產(chǎn)品有所區(qū)別。
那么我們到底需不需要選擇付費(fèi)方案?大家手頭的資金是否充裕?利用社區(qū)版支持商業(yè)用例是不是不太公平?企業(yè)版當(dāng)中的額外功能難道僅僅屬于引誘我們付錢的宣傳噱頭?即使大家并不糾結(jié)于以上問題,那么以下幾條仍然需要認(rèn)真考量:我們該選擇哪個版本?采用哪種開源許可?使用哪些功能集?
缺少原生JSON支持能力
可能大家還沒有意識到MySQL的悠久歷史——別擔(dān)心,親自安裝一下,各位就會意識到需要添加多少驅(qū)動程序才能讓其正常運(yùn)行。MySQL一般會使用3306端口,而且通常把數(shù)據(jù)拆分成自己的一種“神秘”格式。如果大家希望利用自己的代碼與之進(jìn)行交互,則必須添加額外的代碼層將MySQL格式轉(zhuǎn)化為更具實(shí)用性的形式。這些通過庫進(jìn)行分發(fā)的代碼層往往要求用戶購買商用許可。
現(xiàn)代數(shù)據(jù)存儲層通常能夠與JSON直接對接。盡管MySQL以及MariaDB現(xiàn)在也擁有將JSON解析為SQL組成部分的能力,但其效果還稱不上理想。相比之下,CouchDB、MongoDB乃至其它新型工具都已經(jīng)開始提供原生JSON接口。
閉源專有模塊的興起
之前我提到過MySQL屬于開源項(xiàng)目吧?事實(shí)上,它只能算是以“開源”為核心,同時提供部分新型閉源專有模塊的項(xiàng)目。程序員們必須接受這一殘酷的現(xiàn)實(shí)。甲骨文公司為自己的辛苦付出賺得回報(bào),而這也是商業(yè)世界所遵循的原則。使用MySQL的醫(yī)院不可能免費(fèi)提供醫(yī)療服務(wù),而使用MySQL的農(nóng)民們也不可能白白提供糧食補(bǔ)給。
雖然給MySQL設(shè)定太高的要求標(biāo)準(zhǔn)并不公平,但我們必須承認(rèn),說其依賴開源機(jī)制取得成功確實(shí)不夠準(zhǔn)確。憑借開源起步并不代表項(xiàng)目團(tuán)隊(duì)必須一條路走到黑。如果企業(yè)用戶希望獲得更多新功能,那么至少需要選擇一家供應(yīng)商并向其付費(fèi)。有時候從甲骨文手中購買現(xiàn)成方案要比內(nèi)部自主研發(fā)成本更低。有時候商用、閉源代碼確實(shí)效果出色??偠灾蠹倚枰鶕?jù)實(shí)際情況作出選擇,而不應(yīng)單純糾結(jié)于開源抑或是閉源。
更多信息請查看IT技術(shù)專欄