吐槽时间到——剑指大家都喜爱的高人气关系数据库
MySQL易于安装、速度相对出色而且包含丰富的功能选项。如果单凭这些还不足以吸引你,它同时也是开源运动当中最具代表性的旗舰性项目之一——它的成功故事告诉我们,一家以开源为立足根基的企业同样能够获得巨大成功。
然而,相信每一位使用过MySQL的朋友都曾经出于某种理由将自己的怒拳挥向屏幕——哐!!!虽然平心而论,我们不可能建立起一套能够存储成千上万条互联网信息的技术体系,又要求其从来不出任何差错。但是,一旦差错出现,一股恨意总会涌上大家的心头——也包括我自己。
在今天的文章中,我们整理出关于这套开源关系数据库的八大漏洞,而这些正是经常导致用户神经错乱的元凶所在。其中一部分并不限于MySQL本身,它们会在各类关系类数据库当中频频出现。但如果不把关系类数据库跟MySQL进行明确划分,那么我们将永远生活在上世纪九十年代。所谓不破不立,正视问题也就是解决问题的第一步(当然,大家也可以选择存在时间还不太长的其它新型数据库,但它们同样也是问题缠身——必然的)。
深层缺陷与特有问题
任何一套规模庞大的软件包都会存在漏洞。不过从深层角度来看,MySQL的各类漏洞已经形成了自己的一套风格与体系。在选择MySQL的同时,大家必须马上集中注意力——因为在这里,NULL的作用在不同情况下会发生改变,而外键约束的效果亦往往与我们的期望不符……就连自动递增都会闹出各种意料之外的麻烦。
MySQL当中存在着几十个这样的小问题,而且它们时不时就要跳出来折腾一番。有鉴于此,一部分用户专门整理出了清晰的错误清单。但MySQL至少拥有一套出色的漏洞报告系统,因此我们可以了解到那些自己尚未意识到或者遇到过的潜在问题。遇上错误别激动,其他人也在经历着同样的命运。
关系表欠缺灵活性
表带来了纪律性,纪律性绝不是坏事——但强迫程序员们不得不按照僵化的预定义列打理数据就很令人头痛了。NoSQL之所以能够在短时间内迅速风靡全球,就是因为它为程序员提供充分的灵活性,允许他们随时对数据模型加以强化。如果需要为联系地址添加一行新内容,大家可以在NoSQL当中轻松通过插入来实现。而如果各位打算添加任何一个完整的新数据块,NoSQL模型也能够顺利加以接纳,而不会强行要求用户以预设方式进行提交。
想象一下,我们可能刚刚创建出一套以整数形式存储邮政编码的表。它的效率很高,而且所采用的强制规则也完全可以接受。接下来,有人发送了一条包含连字符的九位邮政编码、或者收到一封包含有加拿大地址邮编的信件,这时我们该怎么办?
这时,相信大家和我一样,听见了梦想破坏的声音……老板希望网站能在几小时内顺利上线,因此我们根本没时间对整套解决方案进行重构。那么程序员该怎么做?也许需要利用一些小技巧将加拿大的邮政编码转化为Base64数字,再将其转换回Base10?又或者利用一条专门的转义码设置辅助表,从而声明真正的邮政编码其实被保存在其它位置?谁知道呢。我们有几十种解决问题的办法,但这些小诀窍总会带来其它潜在麻烦。不过没辙,时间紧迫,网站不能按时上线、我们是要丢饭碗的。
MySQL的关联规则原本希望能让每位用户都抱有诚实谨慎的好心态,但实际上却让我们不得不通过小聪明来规避这种约束。
JOIN
曾几何时,将数据拆分成多个表代表着计算机科学领域的一大卓越进步。这不仅意味着我们能够显著降低表的大小,同时也为用户带来良好的简化效果。但在JOIN语句当中,这种纪律性与收益开始要求我们为之付出代价。
在SQL当中,还没有哪部分组件能像JOIN这样逼迫开发人员建立一系列复杂语句,并承受由此带来的混乱与绝望。在此之后,存储引擎还需要找到最优方式来高效解压这些JOIN语句。总而言之,这相当于开发人员被迫建立起复杂的查询表述,而数据库则被迫对其进行梳理。
正因为如此,很多追求速度表现的开发人员干脆放弃了这一进步,转而采用非规范化方式处理。相较于对条目进行拆分,大家直接将数据对象汇总成一个巨大的表,而这就规避了其复杂性。如此一来,运行速度不仅更快,服务器也不至于(频繁)出现内存溢出状况。
如今磁盘存储空间已经相当廉价。市场上已经出现了单磁盘8 TB产品,而容量更大的方案也即将亮相。所以相信在不久的将来,我们将彻底告别该当活剐的JOIN。
混乱的fork
没错,稳定且受到良好支持的MySQL fork能够刺激市场竞争并带来更多后备选项,但其同时也会引发混乱与困惑。更糟糕的是MariaDB这款fork的出现——作为Monty Widenius负责运营的项目,其背后的支持人员同时也参与了MySQL的开发。那么MariaDB到底值不值得我们采用并信赖?或者说我们更应该选择MySQL?我们是否应当坚持使用使用由该数据库原始开发者们所提供的中心代码?或者转而投向技术水平更高且技术成果更酷的新阵营的怀抱?
除此之外,我们又该如何解读关于兼容性方面的信息?一方面,开发团队告诉我们MariaDB与MySQL在相当程度上能够实现互换。但在另一方面,可以肯定的是二者之间仍然存在差异——为什么非要脚踏两条船并为此苦苦挣扎?也许双方的性能表现接近,而我们的查询也能够在其中以同样的方式起效?但实际情况可能并非如此——或者随着两个项目的持续发展而出现背道而驰的局面。
存储引擎让人晕头转向
MySQL并不属于真正的单一数据库;它实际是打着统一的旗号,暗藏众多更为具体的细节内容。在发展初期,它使用的引擎名为MyISAM,其速度出色但在一致性方面有所欠缺。但这不算什么大事,因为有时候我们确实需要更理想的速度水平,而且能够承受一致性方面的妥协。
但在人们需要更多方案时,InnoDB携完整的事务支持能力登场了。但它的表现仍然无法令人完全满意。时至今日,我们面对着20种存储引擎选项——其数量远远超出了驱动数据库管理实例的实际需要。诚然,能够在无需重写SQL的前提下在不同引擎之间往来切换有时候确实是件好事,但由此带来的麻烦同样不容忽视。我到底该为自己的表选择MyISAM还是InnoDB?又或者最好是以CSV格式进行数据导出?
利益动机
作为一款成功的开源产品,MySQL仍然代表着一整套由专业开发人员构建、且需要据此获得回报的业务体系。尽管大部分用户能够通过开源许可免费享受由此带来的出色功能,但该公司显然需要赚取充足的利润才能持续、健康、稳定地保持发展。这就意味着,以“社区版”旗号免费发布的版本肯定要与面向企业的完整产品有所区别。
那么我们到底需不需要选择付费方案?大家手头的资金是否充裕?利用社区版支持商业用例是不是不太公平?企业版当中的额外功能难道仅仅属于引诱我们付钱的宣传噱头?即使大家并不纠结于以上问题,那么以下几条仍然需要认真考量:我们该选择哪个版本?采用哪种开源许可?使用哪些功能集?
缺少原生JSON支持能力
可能大家还没有意识到MySQL的悠久历史——别担心,亲自安装一下,各位就会意识到需要添加多少驱动程序才能让其正常运行。MySQL一般会使用3306端口,而且通常把数据拆分成自己的一种“神秘”格式。如果大家希望利用自己的代码与之进行交互,则必须添加额外的代码层将MySQL格式转化为更具实用性的形式。这些通过库进行分发的代码层往往要求用户购买商用许可。
现代数据存储层通常能够与JSON直接对接。尽管MySQL以及MariaDB现在也拥有将JSON解析为SQL组成部分的能力,但其效果还称不上理想。相比之下,CouchDB、MongoDB乃至其它新型工具都已经开始提供原生JSON接口。
闭源专有模块的兴起
之前我提到过MySQL属于开源项目吧?事实上,它只能算是以“开源”为核心,同时提供部分新型闭源专有模块的项目。程序员们必须接受这一残酷的现实。甲骨文公司为自己的辛苦付出赚得回报,而这也是商业世界所遵循的原则。使用MySQL的医院不可能免费提供医疗服务,而使用MySQL的农民们也不可能白白提供粮食补给。
虽然给MySQL设定太高的要求标准并不公平,但我们必须承认,说其依赖开源机制取得成功确实不够准确。凭借开源起步并不代表项目团队必须一条路走到黑。如果企业用户希望获得更多新功能,那么至少需要选择一家供应商并向其付费。有时候从甲骨文手中购买现成方案要比内部自主研发成本更低。有时候商用、闭源代码确实效果出色。总而言之,大家需要根据实际情况作出选择,而不应单纯纠结于开源抑或是闭源。
原文标题:8 MySQL gotchas worth a rant