Oracle一个CPU核心的许可证卖47500美元。一台普通的双路16核服务器,光数据库软件就要152万美元,每年还有22%的维保费。
MySQL免费。
这两个东西居然是同一个公司(Oracle Corporation)的产品。而且论装机量,MySQL比Oracle多得多——全球互联网公司几乎清一色在用它。
一个卖天价,一个白送,它们到底差在哪?SQL Server又凭什么在中间活得好好的?
装一遍就知道了
你装MySQL,下载一个压缩包解压,改个配置文件,mysqld --initialize 然后 mysqld &,完事。整个过程可能不到五分钟。MySQL就是一个进程,几十兆内存就能跑起来。
你装Oracle,光看安装文档就要半小时。Oracle是一组进程群——启动之后你用 ps 看,会发现一堆后台进程同时在跑:DBWR在刷脏页、LGWR在写redo日志、PMON在回收死连接、SMON在做实例恢复、CKPT在触发检查点。每来一个客户端连接,Oracle还要fork一个专用服务进程伺候它。
# Oracle 启动后的进程列表(简化)
ora_pmon_ORCL
ora_smon_ORCL
ora_dbw0_ORCL
ora_lgwr_ORCL
ora_ckpt_ORCL
# ... 还有一堆
一台机器上跑十个MySQL实例很正常。跑十个Oracle实例?你的服务器可能先躺了。
这不是缺陷,是设计取舍。Oracle每个进程独立运行,一个挂了不影响别的,隔离性拉满。MySQL所有连接共用一个进程里的线程,轻量,但一个线程搞崩了理论上能把整个mysqld带走。
SQL Server也是多线程,但它搞了个狠活——自己写了一套线程调度器叫SQLOS,不用操作系统的调度。线程什么时候让出CPU,SQLOS说了算。好处是调度策略可以针对数据库场景深度优化,坏处是某个线程卡死不让出CPU的话,整个调度都堵了。
所以Oracle的部署形态就是"一台大机器专门跑一个数据库"。MySQL反过来,资源占用少,启动快,天然适合云和容器化,一台机器上塞好几个实例也不心疼。
Oracle凭什么卖那么贵
Oracle贵,但你确实能看到钱花在哪了。
RAC(Real Application Clusters)。 多台服务器各自跑一个Oracle实例,但共享同一份存储上的数据库。一个节点挂了,其他节点还在跑,业务几乎无感知。MySQL的主从复制?主库挂了你得等从库追完binlog才能切,这中间的几秒到几十秒,对银行来说就是事故。
Data Guard。 容灾方案。主库在北京,备库在上海,redo log实时同步。北京机房出事了,上海可以接管。MySQL也能搞类似的架构,但你得自己拿一堆社区工具拼——Orchestrator做切换、ProxySQL做流量转发、GTID做复制定位——出了问题没人兜底。
闪回技术。 有人误删了一张表的数据。MySQL呢?祈祷你有binlog,然后写个脚本从binlog里把数据捞回来。Oracle?一条命令:
FLASHBACK TABLE orders TO TIMESTAMP (SYSTIMESTAMP - INTERVAL '1' HOUR);
一小时前的数据直接回来了。
银行不怕数据库慢一点,怕的是丢数据、怕的是业务中断。RAC、Data Guard、闪回,全是在解决"出了事怎么办"的问题。Oracle卖的不是性能,是安全感——出了问题可以开SR(Service Request),Oracle的工程师远程帮你查。
MySQL出了问题你去哪找人?Stack Overflow发帖等回复?
免费的MySQL怎么打赢的
MySQL走的是完全不同的路——单机能力不跟Oracle比,靠数量堆上去。
互联网公司的数据库实例动辄几千台。阿里巴巴内部的MySQL实例数量是六位数级别的。按Oracle的价格算,一年光许可证就要花几个亿——这笔钱够养一个几百人的DBA团队自己搞了。
实际上这就是互联网公司的选择:用免费的MySQL,养自己的数据库团队来搞定高可用、分库分表、备份恢复。阿里搞出了AliSQL,腾讯搞出了TXSQL,美团也有自己的MySQL分支。大公司有能力自己改内核,不需要Oracle的原厂支持。
MySQL还有个Oracle没有的优势:可插拔存储引擎。 MySQL的架构分成Server层和存储引擎层,中间用Handler API连接。默认的InnoDB处理事务型业务,Facebook搞了个MyRocks用LSM树优化写入密集场景。Oracle和SQL Server的存储引擎是焊死的,你用也得用,不用也得用。
不过这个"优势"也留下了历史包袱。MySQL有两套日志——Server层的binlog和InnoDB的redo log,两套日志之间要用两阶段提交来保证一致性。Oracle只有一套redo + undo,没这个问题。
MySQL崩溃恢复的时候要同时对比binlog和redo log才能判断事务是不是真的提交了——架构分层的代价。
SQL Server在闷声发财
技术社区里提到数据库,基本就是MySQL、PostgreSQL、Oracle轮着聊。SQL Server?偶尔被提一嘴,通常是"那个只能跑在Windows上的"。
但实际装机量完全是另一回事。全国大量的制造业ERP、医院HIS系统、政务OA、零售POS系统跑的都是SQL Server。这些系统的开发者不在技术社区发声,但它们每天处理的是真金白银的业务数据。
SQL Server能在这些场景站稳,说白了就是省心。
它的管理工具SSMS(SQL Server Management Studio)是真的好用。可视化建表、拖拽式备份还原、图形化的执行计划分析、内置的性能调优顾问——一个普通的IT运维,看几天文档就能把数据库管起来。
MySQL呢?一堆参数要调,高可用要自己搭,备份恢复要写脚本。Oracle呢?先花三个月学完OCA的课程再说。
SQL Server加上Windows Server加上.NET,一套微软技术栈从操作系统到数据库到应用层全包了。出了问题一个微软的support电话就行。IT预算有限、没有专职DBA的中小企业,很难抗拒这种"全家桶"。
MySQL迁到SQL Server,上线就炸
如果你从MySQL迁移到SQL Server(或者反过来),有一个坑是一定会踩的。
MySQL的InnoDB默认就开了MVCC——读写不互相阻塞,SELECT不会被UPDATE挡住,这是天然的。
SQL Server的默认行为不是这样。它的READ COMMITTED隔离级别默认用的是锁,不是MVCC。一个UPDATE没提交,所有读同一行的SELECT全部阻塞等着。
-- SQL Server:不开这个,读写就会互相阻塞
ALTER DATABASE MyDB SET READ_COMMITTED_SNAPSHOT ON;
很多从MySQL迁过来的团队一上线就发现"怎么数据库这么慢",查了半天才发现是读写互相阻塞。
反过来也有坑。从SQL Server迁到MySQL的团队偶尔会发现——MySQL的REPEATABLE READ下居然不会出现幻读(InnoDB用了间隙锁),SQL Server在同样的隔离级别下是会的。
同一个SQL标准,三种数据库三种行为。
UUID做主键,MySQL和Oracle差了十倍
实际开发里还有一个经常引发困惑的差异。
InnoDB的表数据是按主键组织成B+树存储的,叶子节点直接存完整的行数据。用自增整数做主键,数据顺序写入,很快。用UUID做主键,36个字符长(varchar存储)、随机分布,每次插入都可能要往B+树的中间塞数据,频繁触发页分裂,性能会差很多。
Oracle不一样。Oracle默认用堆表——数据按插入顺序往后堆,主键只是个约束,不影响物理存储。所以Oracle用UUID做主键完全没问题。
SQL Server和InnoDB类似,默认也会按主键建聚集索引。但SQL Server灵活一些——你可以选择不建聚集索引,也可以在非主键列上建。
这个差异在MySQL开发者跳到Oracle团队、或者Oracle开发者接手MySQL项目的时候经常引发困惑。MySQL开发者到了Oracle组发现"怎么主键用varchar都没事",Oracle开发者接了MySQL项目发现"怎么换个主键类型性能差了十倍"。
写CRUD的时候三个数据库几乎没区别,踩到架构层的差异才会懵。不过InnoDB的Buffer Pool对应Oracle的SGA Buffer Cache,redo log对redo log,undo log对undo tablespace——概念全是对应的,搞透一个,另外两个上手很快。