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