开源数据库,第三部分:选择数据库

作者:Reuven M. Lerner

如果您是一名应用程序开发人员,您可能正在处理大量数据。而且,如果这些数据比哈希表更复杂,您可能需要考虑将部分或全部数据移动到关系数据库中。关系数据库旨在可靠且灵活地检索数据。关系数据库的魔力不是使用二维表来存储所有信息,而是表可以以多种不同的方式组合,并使用 SQL 查询语言进行操作。

正如我们在我最近两期 LJ 数据库文章中看到的那样,开源程序员很幸运能够拥有多种数据库选择。到目前为止,最流行的两个开源关系数据库是 MySQL 和 PostgreSQL。两者都拥有庞大且忠实的追随者,并且每个版本都在不断改进。

当我上面写“庞大且忠实的追随者”时,我并没有开玩笑。长期以来,MySQL 和 PostgreSQL 一直是开源世界主要口水战的中心。如果有人在 Slashdot 上胆敢说一些关于其中一种产品的事情,您可以肯定,很快就会有人写一篇关于另一种产品的恶劣(且通常幼稚)的评论。这些分歧通常反映了不了解情况的用户的下意识反应,但也不乏来自知名且了解情况的这些产品用户的攻击。

我认为在某些情况下,MySQL 或 PostgreSQL 都是合适的选择。在过去的十年中,我在工作中强烈偏爱 PostgreSQL——但确实有些时候 MySQL 似乎是更合适的解决方案。

因此,尽管我个人有偏见,并且冒着在开源社区内引发口水战的风险,我现在结束关于开源数据库的系列文章,对 MySQL 和 PostgreSQL 在许多不同类别中进行比较。我希望当您读完本文时,您会明白选择数据库几乎从来都不是找到“最快”或“最好”的产品的问题,因为没有一种方法可以衡量关系数据库服务器的质量或适用性。相反,我希望您能够根据它们自身的优点来考虑这些,而不是根据如此广泛的宣传。

数据完整性

数据库的首要任务也许是可靠地存储和检索数据。正如您不希望使用偶尔丢失数据的硬盘一样,您也不希望将东西放入偶尔会篡改其内容的数据库中。即使可靠性是以牺牲速度为代价的,也是如此。

数据库世界中可靠性的黄金标准有一个首字母缩写词,ACID(原子性、一致性、隔离性和持久性)。这意味着在数据库的所有情况下,以下情况都成立

  • 原子性:每个查询都保证完成或不完成,不会出现任何中间或不完整状态。

  • 一致性:数据库在事务处理前后始终处于合法状态。

  • 隔离性:每个事务都与其他操作分开发生,因此您不会有两个事务相互干扰。

  • 持久性:事务会持久保存,通常通过存储在文件系统中来实现。

自十年前我开始使用 PostgreSQL 以来,PostgreSQL 社区对 ACID 的态度一直没有改变,将其置于尽可能高的优先级。这并不意味着 PostgreSQL 缺乏其他功能,而是意味着开发人员致力于确保存储在 PostgreSQL 系统中的数据将是一致且可靠的,即使您做了糟糕的事情,例如发出kill -9或拔掉电源。

在过去几年中,PostgreSQL 开始为事务和数据库稳定性提供更好的支持,使用预写式日志 (WAL),描述数据库执行的每个操作。这些 WAL 文件可用于从灾难中恢复,甚至将数据库恢复到历史上的早期时间点——这种功能称为时间点恢复 (PITR)。因此,如果您知道昨天发生了某些事情,但数据库在两天前运行良好,您可以使用 PITR 恢复到更早、更稳定的状态。最近版本的 PostgreSQL 还支持两阶段提交,这是一种您在分布式系统中可能看到的事务类型,其中多个服务器必须协调其操作。

多年来,MySQL 对 ACID 的态度不一。当我在 1995 年首次开始使用 MySQL 时,作者的态度是事务应由应用程序处理,而不是数据库处理。实际上,早在 2000 年,MySQL 的待办事项列表中就包含了与生产质量的事务安全表相关的任务。这导致了 MySQL 和 PostgreSQL 社区之间的大量恶感,后者的一些成员有时声称任何关键数据都不应存储在 MySQL 中。

好消息是,现代版本的 MySQL 确实支持事务安全表,使用 InnoDB,一个根据 GPL 发布的第三方产品,已集成到 MySQL 中多年。此外,InnoDB 似乎使用了 PostgreSQL 和 Oracle 多年来使用的技术,例如 MVCC(多版本并发控制)。坏消息是,至少我看到的一些基准测试表明,InnoDB 在扩展到大量并发查询时存在一些问题。

此外,开发 InnoDB 的公司最近被 Oracle 收购,这可能会让一些人担心未来的许可、开发和定价问题。就目前而言,后一个问题似乎并不严重,因为 Oracle 和 MySQL 在 2006 年签署了一份合同,延长了 InnoDB 的许可。但是,MySQL 似乎并没有冒险,并聘请了几位专家来创建一个新的表结构,该结构将归 MySQL 所有,因此不受此类业务问题的影响。

我个人认为,真正的 ACID 合规性始终是一件好事,就像汽车中的安全带一样。当然,您可以不系安全带开车,很可能什么都不会发生在你身上。但是,不可能预测何时会发生不好的事情,在这种情况下,您真的不想没有安全带。同样,如果您的数据对您很重要,最好确保它将以完整性持久保存。

一个相关问题与每个数据库强制执行约束和限制的程度有关。PostgreSQL 在这些问题上往往非常严格,拒绝接受非法数据。MySQL 试图更加宽容和灵活,但这可能会导致存储奇怪和非法的数据。

例如,考虑以下 MySQL 命令集,我们在其中创建一个名为 foo 的表,其中包含一个类型为 DATE 的单列(名为 a)

mysql> CREATE TABLE foo (a date);
Query OK, 0 rows affected (0.08 sec)

mysql> INSERT INTO foo (a) VALUES ('2007-feb-30');
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> SELECT * FROM foo;
+------------+
| a          |
+------------+
| 0000-00-00 |
+------------+
1 row in set (0.00 sec)

相比之下,这是 PostgreSQL 中发生的情况

atf=# CREATE TABLE foo (a date);
CREATE TABLE

atf=# \d foo
Table "public.foo"
 Column | Type | Modifiers
--------+------+-----------
 a      | date |

atf=# INSERT INTO foo (a) VALUES ('2007-feb-30');
ERROR:  date/time field value out of range: "2007-feb-30"

可以配置 MySQL 在这些问题上更加严格,但大多数用户不会想到这样做,并且会遇到表中的非法值。

鉴于 MySQL 的政治和技术问题,以及 MySQL 中奇怪(且可能危险)的默认行为,我认为 PostgreSQL 在数据完整性问题上具有很大的优势。

功能

MySQL 和 PostgreSQL 提供了非常多的内置功能,其中许多功能是根据社区请求和反馈添加的。两者都提供了大量的数据类型,这些数据类型可以在单个行中混合和匹配,而没有限制。(曾经困扰 PostgreSQL 版本的非常有限的行长度限制现在已成为历史,我很高兴地说。)现在,这两个数据库都支持 Unicode 字符;MySQL 同时支持 UCS-2 和 UTF-8 编码,而 PostgreSQL 仅支持后者。

这两个数据库还提供了大量操作数据的函数,包括字符串和日期。能够比较和排序日期或查找时间戳在过去 24 小时内的所有行非常方便。PostgreSQL 的 interval 数据类型(描述一段时间长度,而不是特定的时间点)已被证明特别有用。MySQL 有许多不同的类型,像我这样的数据库纯粹主义者对此感到不满,例如 SET 和 ENUM,但这些类型无疑在许多用户中很受欢迎。

在 PostgreSQL 具有优势的许多领域,MySQL 开始迎头赶上。长期以来,PostgreSQL 用户一直能够创建新的数据类型和操作这些类型的功能。实际上,PostgreSQL 为开发人员提供了非凡的能力,可以使用多种语言编写服务器端函数,包括 SQL、Perl、Python、Java、Tcl 和 R 统计语言。MySQL 不允许创建新的数据类型,但最近的版本确实提供了编写服务器端函数和存储过程的能力。

MySQL 提供了一个用于全文搜索的内置解决方案,通过在文本字段上使用特殊类型的索引来实现。但是,此索引存在一些重要的限制,例如它仅适用于 MyISAM 表。鉴于这些表既不支持外键也不支持事务,我对建议将它们作为解决方案有点不安。

PostgreSQL 的全文搜索解决方案 (tsearch2) 存在相反的问题。虽然它很强大,并且在 PostgreSQL 的标准事务表中运行良好,但它需要一些工作来配置和安装。大多数管理员和程序员都可以在短时间内成功安装它,但尽管如此,内置功能和需要添加的功能之间还是存在差异。

PostgreSQL 有许多内置功能,MySQL 尚未实现或计划在未来版本中发布。其中包括在查询中的任何位置使用子查询的能力、使用序列(而不是简单的自动递增列)、允许用户修改给定表上查询解释方式的规则以及列值的 CHECK 约束。最近版本的 MySQL 现在包含以前仅在 PostgreSQL 中提供的功能,例如触发器和视图。

总的来说,PostgreSQL 开发团队似乎比 MySQL 更强调 SQL 标准,尽管 MySQL 开发人员似乎越来越意识到这种需求,现在为那些希望始终在标准兼容模式下工作的人员提供了 --ansi 命令行开关。

MySQL 和 PostgreSQL 都非常易于使用。每个数据库都带有一个功能丰富的命令行客户端程序,允许您通过发送 SQL 查询来操作数据库。我已经习惯了 PostgreSQL 命令行的一些功能,例如扩展输出 (\x)。

随着时间的推移,这两个数据库的命令行界面都变得更加有用。虽然 MySQL 界面可能看起来命令较少,但这部分是因为 MySQL 通过 SQL 查询(例如,SHOW TABLES)提供了一些数据,这在 PostgreSQL 中需要更复杂的查询,从而导致创建了简写命令 \dt。这两个命令行界面都使用 GNU readline,使编辑和重新执行查询变得容易。两者都允许用户使用 \e 命令编辑上一个查询。

总的来说,可以公平地说,PostgreSQL 提供了 MySQL 功能的超集,除了少数问题(例如,内置文本索引)。PostgreSQL 不具备的那些功能,例如新的数据类型和函数,可以轻松添加到系统中,而无需重新编译或以其他方式修改核心 PostgreSQL 服务器。话虽如此,我认为 MySQL 的功能不容小觑,并且对于您可能正在编写的大多数应用程序来说可能绰绰有余。

管理

MySQL 和 PostgreSQL 都非常易于管理,尤其是在中小型情况下。您可以(可选)更改一些配置选项,启动服务器,然后就可以离开了。实际上,没有比这更多的事情要做。对于任何使用过更大型数据库系统(例如 Oracle)的人来说,这是一个令人耳目一新的变化。但是,这两个系统的运行方式略有不同。

PostgreSQL 依赖于几个外部 UNIX 级命令来创建和管理数据库和用户,以及 PostgreSQL 服务器的活动。没有中央 PostgreSQL 管理程序。相比之下,MySQL 有一个中央 mysqladmin 程序,用于处理与服务器启动和关闭以及数据库的创建和销毁有关的大多数功能。用户的创建和管理是通过操作 mysql 数据库中的表来处理的。

PostgreSQL 中 mysql 数据库的对应物是特殊的系统表和视图,所有这些表和视图都以 pg_ 前缀开头。这些表虽然是系统运行所必需的,但大多数程序员可以轻松地忽略它们,并且仅在尝试调整系统或找出如何优化查询时才发挥作用。

这两个程序都提供了基于 GUI 的管理工具,以及用 PHP 编写的基于 Web 的工具。老实说,鉴于我对命令行系统在数据库方面的熟悉程度(和偏好),这些年来我并没有过多地使用这些工具。但是,我对这两组 GUI 程序的体验都是积极的,我的印象是它们既稳定又安全,而且非常有用。

PostgreSQL 独有的另一个管理方面是需要从数据库中“清理”死行,以将它们返回到操作系统或返回到可能从空间中受益的其他行。此外,PostgreSQL 的 vacuum 函数访问死行,并使用它收集的统计信息来通知优化器和查询计划器。现在,自动清理守护进程会自动为大多数人处理此问题,从而消除了长期以来需要在 cron 中安排它的需求。

目前特别热门的一个管理领域是复制。许多网站和其他应用程序正在突破其数据库服务器的限制,将工作分配到多个服务器之间将非常有用。当然,这引发了分布式进程之间的数据完整性和同步问题。解决该问题的简单方法是在不同的服务器之间建立主/从关系,UPDATE 和 INSERT 操作仅在主服务器上进行,而 SELECT 操作在从服务器上进行。MySQL 和 PostgreSQL 都存在针对此问题的解决方案,尽管 PostgreSQL 解决方案 (Slony) 是标准包的外部解决方案,并且显然可能难以安装和配置。

更复杂的设置涉及使用两个主数据库服务器。MySQL 似乎在该领域处于领先地位,并推出了一种相对较新的集群工具。但是,多年来一直呼吁使用此类工具的 PostgreSQL 用户似乎即将实现他们的愿望。

最后,如果无法执行定期备份,任何数据库服务器都将毫无价值。pg_dump 和 mysqldump 是命令行程序,可以将数据库的当前内容转换为文本文件。此类转储文件非常有用,可用于在必要时重建数据库。

我认为,在管理方面,这两个数据库产品是相同的——除非您需要复制,在这种情况下,您可能会从 MySQL 更丰富的经验和复制集成中获益。

性能

多年来,MySQL/PostgreSQL 口水战中提出的一个主张与速度有关。MySQL 粉丝经常声称他们的系统更快,尤其是在只读任务方面,这使其成为大多数数据都是读取的网站的更好选择。相比之下,PostgreSQL 倡导者声称他们的系统比 MySQL 更好地承受大负载。

我没有进行任何自己的基准测试,但我之所以不愿意这样做,是因为我承认自己没有资格创建良好的基准测试,而不是因为我认为这两个系统是相同的或者性能不重要。此外,正如我之前所述,我认为性能次于数据完整性。我宁愿拥有一个缓慢、可靠的数据库,也不愿拥有一个快速但偶尔会破坏我的数据的数据库。

从我看到的基准测试来看,当处理少量客户端或只读数据时,MySQL 的速度确实比 PostgreSQL 快。但是,过去几年我看到的所有比较都表明,随着添加到系统中的客户端数量增加,PostgreSQL 处理负载的能力更强。

这是否意味着 PostgreSQL 总是更快?当然不是。但这确实意味着在特别受欢迎的网站上,PostgreSQL 可能会更好地保持稳定。

也许我只是天真,但我几年前就决定,在数据库方面,我将在很大程度上忽略性能辩论。MySQL 和 PostgreSQL 都有大量的追随者,并且已在大规模系统中使用。数据似乎表明 PostgreSQL 具有优势,但是有足够多的人在大型网站上使用 MySQL,我不得不假设它对他们来说运行得足够好。

支持

最后,如果不提及支持,任何比较都是不完整的。我们可以考虑几种类型的支持——从开源社区的实力到支持(和开发)软件的公司数量和质量,再到支持每个数据库的第三方应用程序的数量。

不可能忽视世界上数量庞大的 MySQL 用户。这导致了大量关于 MySQL 的书籍、教程和邮件列表的涌现——其中一些(但并非全部)是由 MySQL 公司本身赞助的。如果基于社区的支持不足以满足您的需求,可以从包括 MySQL AB 在内的多家公司购买 MySQL 的商业支持。

PostgreSQL 的社区较小,可用的书籍和教程也较少。但是,我的经验是,社区对问题和建议反应迅速,并且主要开发人员通常非常愿意回答来自各个级别用户的问题。

许多开源软件包同时支持 MySQL 和 PostgreSQL。但是,很少找到专门支持 PostgreSQL 的软件包,并且很容易找到仅支持 MySQL 的软件包。这一直是 PostgreSQL 社区成员感到沮丧的根源;但是,除了请求补丁或贡献此类补丁之外,似乎没有人可以对此做太多事情。

最近在 PostgreSQL 主要邮件列表上的一个主题询问了支持该数据库的 CRM 软件包。虽然有一些,但肯定有一些关于其他开源项目缺乏 PostgreSQL 的抱怨。这些项目通常由小组志愿者组成,他们很少理解如何使他们的 SQL 更具可移植性,从而更容易在多个品牌的数据库上使用。

关于支持的底线是,虽然 PostgreSQL 支持非常出色,但 MySQL 支持是压倒性的。如果这里有赢家,那就是 MySQL。

结论

那么,您应该为您的下一个数据库任务选择 MySQL 还是 PostgreSQL?在所有条件相同的情况下,我强烈推荐 PostgreSQL。它的社区可能较小,并且印刷和 Web 上可用的资源较少。但是,它具有更多功能来确保数据完整性,其功能在很大程度上是 MySQL 的超集,并且它始终提供事务和引用完整性,而无需指定特定类型的表。

话虽如此,使用 MySQL 也有原因:如果您已经在使用它,如果您需要商业或社区支持,如果您需要复制,或者如果您正在使用的软件与 PostgreSQL 不兼容,那么 MySQL 是一个不错的选择。只需确保使用 InnoDB 表,这样您就可以利用数据库一直以来应该做的事情——确保数据质量。

资源

PostgreSQL 主页是 www.postgresql.org。同样,MySQL 主页是 www.mysql.org。每个主页都发布了最新的手册,以及软件、驱动程序和讨论列表。

比较这两个数据库的管理和编程的表格可在 linuxboxadmin.com/articles/postgresql-for-mysql-users.php 上找到。

最近对这两个数据库性能的比较可在 www.mysqlperformanceblog.com/2006/11/30/interesting-mysql-and-postgresql-benchmarks 上找到,该链接指向以下内容:tweakers.net/reviews/657。

最后,欧洲核子研究中心 CERN 对这两个数据库(可能有点过时)以及 Oracle 进行了比较,可在 dcdbappl1.cern.ch:8080/dcdb/archive/ttraczyk/db_compare/db_compare.html 上找到。

Reuven M. Lerner,一位长期的 Web/数据库顾问,是伊利诺伊州埃文斯顿西北大学学习科学博士候选人。他目前与妻子和三个孩子住在伊利诺伊州斯科基。您可以在 altneuland.lerner.co.il 阅读他的博客。

加载 Disqus 评论