MySQL 值得再次关注
在 1995 年初,当时 Windows 95 还是个虚无缥缈的概念,而 Red Hat 还是 Slackware 的新兴用户友好替代品时,我在媒体巨头时代华纳的“探路者”网站工作。像所有媒体公司一样,时代华纳意识到网络将会兴起,但不确定这将如何发生。
因此,它聘请了一批程序员和设计师,并给我们机会尝试不同类型的设计和应用程序。这是一份很棒的工作,与一些有创意、聪明且有趣的人一起工作。而且,在我任职期间,我创建了各种应用程序——测验、邮件自动回复器、游戏、搜索引擎,甚至还有个性化版本的《Money》杂志的“最佳城市”排名。
随着我构建的应用程序变得越来越复杂,很明显,我经常用于数据存储和检索的文本文件对于像我们这样庞大且受欢迎的网站来说既不高效也不够灵活。最后,有人向我介绍了我们新聘请的数据库专家,他教我关系数据库和 SQL 的奇妙之处。我被迷住了,并且喜欢使用我们安装的数据库服务器。
当我想在我的家用 Linux 机器上获得 SQL 的好处时,不幸的是,我的选择有限。我找到了一些被废弃的开源数据库项目,但没有一个像时代华纳的 Sybase 服务器那样强大,甚至不在同一个级别。
所以,你可以想象当我发现 MySQL 时有多么高兴。不,它并没有做 Sybase 所做的所有事情,而且它不是在开源许可证下发布的。但是,它是免费的,易于安装,并且具有足够的功能让像我这样的人相对满意。互联网服务提供商也有类似的感觉,并开始在他们的系统上安装它——首先是作为相对于竞争对手的竞争优势,然后是因为其他所有人都在基本配置中包含它。
快进十多年,MySQL 已成为迄今为止最著名的开源关系数据库。蒙蒂·维德纽斯 (Monty Widenius) 和大卫·阿克斯马克 (David Axmark) 在他们还是唯一的全职 MySQL 程序员时我就见过他们,现在他们正处于大型企业金字塔的顶端。MySQL AB 现在根据 GNU 通用公共许可证 (GPL) 分发其产品,并为需要的人提供闭源许可证。与往常一样,它在非常多的不同操作环境中运行。而且,世界各地的人们仍然以狂热的速度进行开发,他们提交补丁和建议。
这是关于开源数据库的三篇文章中的第一篇。本月,我将讨论 MySQL,包括其使用、功能和问题。下一篇文章将包括对 PostgreSQL 的类似分析,该系列中的第三篇文章将比较这两个数据库。
MySQL 的成名原因之一是人们可以轻松上手使用它。而且,的确,当您将 MySQL 与许多商业数据库进行比较时,它非常简单。您安装它(通常使用 RPM 或 Deb,但从源代码编译它也很简单),并使用以下命令启动数据库服务器safe_mysqld。(您也可以使用普通的 mysqld 命令,但那样您就无法从 safe_mysqld 提供的一些幕后管理中受益。)
启动服务器后,您可以创建一个或多个数据库。(我承认,MySQL 通常被称为数据库有点令人困惑,而实际上,它是一个数据库服务器,为您提供创建一个或多个数据库的机会。每个数据库包含一个或多个二维表。)要创建数据库,请使用 mysqladmin 程序
mysqladmin create testdb
根据您的配置,上述命令很可能顺利运行——特别是如果您以 Linux 下的 root 用户身份登录。但是,您的系统管理员可能(明智地)决定为 MySQL root 用户设置密码,在这种情况下,您需要键入
mysqladmin -p create testdb
-p 选项告诉 mysqladmin 您想为此帐户输入密码。您还可以使用 -u 选项指定 root 用户或任何其他用户,如
mysqladmin -u mysqlroot -p create testdb
创建数据库后,您可以使用 mysql 客户端程序连接到它
mysql -u mysqlroot -p testdb
请注意,我再次指定了用户名,并且我想输入密码。我将在下面回到权限主题;现在,我们假设这种组合有效。
在客户端中,您可以发出任何您想要的 SQL 命令,它将立即执行。例如,我们可以创建一个新表
CREATE TABLE Classes ( class_name TEXT NOT NULL, room_number INTEGER NOT NULL, starting_date DATE NOT NULL, ending_date DATE NOT NULL, instructor TEXT NOT NULL );
上面表格的问题之一是它缺少唯一的 primary key。这使得从另一个表格引用 Classes 表格变得困难。我们可以使用大学注册系统分配给课程的名称,但这不能保证它是唯一的。此外,明年提供同名课程时我们该怎么办?因此(以及其他原因),通常的做法是创建一个“人为的”primary key,其目的是唯一标识数据库中的一行。
在 MySQL 中,我们可以使用 AUTO_INCREMENT 关键字最轻松地做到这一点。例如
CREATE TABLE Classes ( class_id INTEGER AUTO_INCREMENT, class_name TEXT NOT NULL, room_number INTEGER NOT NULL, starting_date DATE NOT NULL, ending_date DATE NOT NULL, instructor TEXT NOT NULL, PRIMARY KEY(class_id) );
如果我们愿意,我们可以使用类 ID 的显式整数值将行 INSERT 到 Classes 中。class_id 定义为 primary key 意味着它既被索引又保证是唯一的。但是,如果我们未能为 class_id 输入显式值,MySQL 会在列中插入一个新值,为我们提供新类的 primary key 值,而无需我们自己计算。
上面的表格定义显示了 MySQL 提供的许多数据类型中的一些。MySQL 提供了许多传统数据类型,例如 NUMERIC 和 VARCHAR,但它也包括许多有符号和无符号数字类型(例如,TINYINT、SMALLINT、MEDIUMINT、INT 和 SIGINT)、许多 CLOB/BLOB 类型(例如,CHAR、BINARY、BLOB 和 TEXT)以及几个与日期和时间相关的类型(DATE、DATETIME 和 TIMESTAMP)。还有 ENUM 和 SET 类型,允许您使用非标准的枚举数据集。
MySQL 还提供了各种各样的运算符,从简单的字符串连接到日期提取,再到我最喜欢的运算符之一 CASE 语句,它允许您在查询中放置 if-then 逻辑。
此外,MySQL 还提供了一个用于全文搜索的系统。这意味着您可以将文本存储在表格的 TEXT 列中,然后识别列(并检索文本),而无需自己对其进行索引。
如果包含的功能套件不适合您的需求,您可以随时编写自己的功能。最近版本的 MySQL 还提供了创建存储过程或函数的能力,这既提高了速度,又集中控制了常用功能。当特定事件发生时(在数据库术语中称为触发器),也可以自动调用存储过程。您还可以使用 C 或 C++ 编写新函数,并在运行时将其加载到 MySQL 中。
到目前为止,MySQL 听起来像是一个不错、灵活的关系数据库。但是,您可能会感到惊讶,开源和数据库社区对 MySQL 存在大量压抑的挫败感,甚至敌意。只需在 Slashdot 上查找最近关于 MySQL 的故事,您就会看到许多评论表明 PostgreSQL、Firebird 或几乎任何其他选择都是更好的解决方案。
其中一部分源于计算机世界,特别是开源社区中历史悠久的竞争传统。多年来,我们看到了 Emacs 和 vi、Perl 和 Python、Linux 和 BSD 以及无数其他配对之间的争斗。
但是,对 MySQL 的敌意部分源于作者早期做出的一些设计决策。例如,旧版本的 MySQL 文档说外键实际上是不必要的,并且此类完整性检查可以在(并且应该)在应用程序中而不是在数据库中处理。许多经验丰富的数据库人员看到这一点,不知道是该笑还是该哭。使用数据库的主要原因是它的可靠性,而不是速度,添加外键检查是提高插入数据可靠性的简单方法。
同样,旧版本的 MySQL 未能锁定表格。如果您想确保在您正在读取(或正在写入)的表格中没有人会写入,则需要在应用程序层显式锁定表格。鉴于多年来在行级锁定(甚至更高级的系统,例如多版本并发控制)方面进行的深入研究,这在许多人看来似乎是倒退了一步。
MySQL 解决这些问题的方法是一种新颖的方法。它没有将这些功能添加到现有的 (MyISAM) 表格结构中,而是可以从许多不同的表格结构中进行选择,每种表格结构都有其自己的一组权衡。就像 Linux 系统管理员可以从各种文件系统中进行选择一样,MySQL 管理员和程序员也可以从几种不同的存储引擎中进行选择。
当然,这种方法存在一些问题。从我的角度来看,最大的问题是 MyISAM 仍然是默认存储引擎,这意味着许多用户实际上由于无知而选择不使用外键和复杂的锁定。许多其他存储引擎似乎用途更有限或用于特定应用程序,例如 MEMORY(用于内存数据库)、BDB(基于 Berkeley DB 的)表格,甚至 FEDERATED(用于远程服务器上的表格)。
一个非常流行的存储引擎 InnoDB 存在一个与之相关的不同问题——开发 InnoDB 的公司今年早些时候被 Oracle 收购。这可能对 MySQL 的开源发行版没有影响,因为 Oracle 继续在 GPL 下提供 InnoDB。但是,鉴于商业级工具箱的重要组成部分现在由主要的数据库竞争对手拥有,这引发了关于 MySQL 商业版本的一些问题。
多年来,人们对 MySQL 在服务器几乎没有或根本没有调整的情况下快速的性能做了很多文章。事实比这要模糊一些;虽然 MySQL 无疑是一个快速数据库,但许多测试都是使用 MyISAM 表格进行的,MyISAM 表格由于缺乏锁定和完整性检查而天生更快。(作为一个类比,我经常说不锁门就离开家更快,但额外的速度通常不值得冒险。)
最新版本 MySQL 中的许多功能都是针对企业客户的,他们的许可证购买正在推动 MySQL 的发展。数据库管理员可能面临的最大瓶颈之一,特别是随着数据量的增长,是磁盘速度。因此,最新版本的 MySQL 提供了表空间(即,在每个表的基础上分配磁盘空间)和分区(即,跨多个文件系统划分表)。表空间仅适用于 InnoDB 表格,但分区适用于所有存储引擎。此外,可以基于列值对表格进行分区,使用哈希函数来决定特定行应放置在哪个分区中。
MySQL 的另一个重要方面是复制和备份。这些对于企业客户至关重要,他们需要数据始终可用,并且需要在瞬间进行备份。最新版本的 MySQL 改进了复制引擎,并且使其更加灵活,从而可以甚至在每行基础上复制表格。
我一直在等待一段时间的另一个功能是 Unicode 支持。虽然并非所有字符串和 regexp 操作都适用于 Unicode,但这对于使用多种语言的人来说是一个很大的福音。
也许 MySQL 最强大的资产是庞大而活跃的用户和开发人员社区。关于 MySQL 的书籍、网站、邮件列表、帮助论坛和代码片段的数量非常惊人。
就 MySQL AB 而言,它一直在定期更新文档,并以惊人的速度推进新功能。 (这表明,尽管开源软件通常可以由志愿者编写,但让付费专业人员参与项目可以极大地加快速度。)特别是,我对在线文档印象深刻,它不仅包含大量示例,还包含智能放置的指向相关主题的链接。
Reuven M. Lerner,一位长期的 Web/数据库顾问,是伊利诺伊州埃文斯顿西北大学学习科学专业的博士候选人。他目前与妻子和三个孩子住在伊利诺伊州斯基。您可以在 altneuland.lerner.co.il 阅读他的网络日志。