- 在更早的 20 年间,MySQL 的前身 UNIREG 被 Monty 开发
- 1994 年瑞典公司 TcX 成立,Monty 是三位创始人之一。次年,这家公司改名为 MySQL AB。
TcX 将 UNIREG 改造为一款支持 SQL 的关系型数据库。 - 1995 年,MySQL 3.11 发布。
- 1999 年,MySQL 3.23 集成 BDB,开始了可插拔存储引擎架构。
- 2000 年,ISAM 改良成 MyISAM,同时 MySQL 基于 GPL 协议开源。
- 2001 年,MySQL AB 和芬兰公司 Infobase Oy 合作,为 MySQL 3.22 带来了 InnoDB 引擎。
重点是事务和行级锁。
注意:InnoDB 是 GPL / 专有协议双授权。 - 2005 年,Innobase Oy 被甲骨文收购。同年, MySQL 5.0 发布。
注意:我们现在数据库系统课的很多概念,触发器,存储过程,视图,游标等都是 5.0 开始支持的。 - 2006 年,Oracle 曾经试图收购 MySQL 但是遭到拒绝。
- 2008-02-26 MySQL AB 被 SUN 10 亿美元收购。
- 2008-11-27 MySQL 5.1,开始支持分区,和主从同步时的行复制(RBR)。
- 2009-04-20 SUN 被甲骨文 74 亿美元收购,收购直到 2010-01-27 才完成。
最重要的存储引擎 InnoDB 终于和 MySQL 版权归于一处了。 - 2010-12-03 MySQL 5.5,InnoDB 成为默认引擎(5.5.5 开始)。
- innodb 改进
- utf8mb4
- metadata lock
- 2013-02-05 MySQL 5.6
- 2015-10-21 MySQL 5.7
- 2018-04-19 MySQL 8.0
- 最新版本是
2020-10-19 发布的 8.0.22
2021-10-19 发布的 8.0.27 (Update @ 2021-11-16)
- 最新版本是
说明:
- 5.6,5.7 应该是现在最常用的两个版本。
8.0 还比较新,我还没有在线上业务中用过。但是有很多我感兴趣的特性。 - 列举的特性可能是在不同子版本引入,开发中可能需要留意不同子版本的差异。
就现在我理解的主流开发思想,对组件应该简单应用,就数据库而言,应该只用来做基础存储,不要涉及复杂功能,不要涉及所谓特性,最要用好几个大版本就在的功能,其他数据库系统都有的功能。
我觉得有点过了。这个另说吧。
MySQL 5.6 新特性
GTID复制。
无损复制。
延迟复制。
基于库级别的并行复制。
mysqlbinlog可远程备份binlog。
对TIME, DATETIME和TIMESTAMP进行了重构,可支持小数秒。DATETIME的空间需求也从之前的8个字节减少到5个字节。
Online DDL。ALTER操作不再阻塞DML。
可传输表空间(transportable tablespaces)。
统计信息的持久化。避免主从之间或数据库重启后,同一个SQL的执行计划有差异。
全文索引。
InnoDB Memcached plugin。
EXPLAIN可用来查看DELETE,INSERT,REPLACE,UPDATE等DML操作的执行计划,在此之前,只支持SELECT操作。
分区表的增强,包括最大可用分区数增加至8192,支持分区和非分区表之间的数据交换,操作时显式指定分区。
Redo Log总大小的限制从之前的4G扩展至512G。
Undo Log可保存在独立表空间中,因其是随机IO,更适合放到SSD中。但仍然不支持空间的自动回收。
可dump和load Buffer pool的状态,避免数据库重启后需要较长的预热时间。
InnoDB内部的性能提升,包括拆分kernel mutex,引入独立的刷新线程,可设置多个purge线程。
优化器性能提升,引入了ICP,MRR,BKA等特性,针对子查询进行了优化。
可以说,MySQL 5.6是MySQL历史上一个里程碑式的版本,这也是目前生产上应用得最广泛的版本。
若干安全性提升(包括密码自动过期 (mysql.user
的 password_expired
))
若干性能提升(优化器,InnoDB)
- 时间支持到微妙(TIME, DATETIME, TIMESTAMP)
- DATETIME 只需要 5Bytes,而不是 8Bytes
- 可以有多个时间类型
DEFAULT current_timestamp() ON UPDATE current_timestamp()
之前只能支持 1 个 TIMESTAMP 类型
数据类型(Data types)
1) 支持更小时的时间粒度,精确到微秒(6位)。
2)以前每个表最多只有一个TIMESTAMP 列可以用当前时间初始化和更新。这个限制没有了。所有TIMESTAMP列都可以设置这2个属性。另外,DATETIME 也支持这些属性了。
3)YEAR(2)类型被抛弃,现存的表中的year(2)列会和以前一样处理,但新建或者修改表结构时会转化为YEAR(4)
InnoDB的增强(The InnoDB storage engine)
1)MySQL 5.6完全集成InnoDB作为默认的存储引擎。同时5.6版本在使用InnoDB上的很多细节做了改进。
2)InnoDB现在可以限制大量表打开的时候内存占用过多的问题(比如这里提到的)(第三方已有补丁)。
3)Innodb redo log大小从最大4GB提高到512GB,通过参数 innodb_log_file_size 配置。
4)Innodb使用了一种新的,更快的算法来检测deadlocks. 所有死锁信息都可以被记录到错误日志。方便分析。
5)Online DDL,几种ALTER TABLE操作不再拷备表,不会阻塞insert,update,delete或者全部写入操作。仍然有一些Alter操作需要重建表,比如增加/删除列,增加/删除主键,改变数据类型等。这也就是所谓的online DDL。(之前版本中DDL操作需要全部加锁重建表)。
6)Innodb强化了几种内部性能,包括拆分kernel mutex来减少竞争,将刷新操作移出主线程,允许使用多个清理线程,以及减少了大内存系统中的buffer_pool竞争。
7)可以通过NoSQL API开发应用访问InnnoDB表。它使用流行的memcached守护进程来响应对于key-value对的Add,Set和GET请求。这样避免了解析和构建query execution plan的成本。你可以使用NoSQL API或者SQL来访问同一份数据。比如:你可以通过NoSQL API快速访问和查询表数据,使用SQL来进行复杂查询以及兼容已有的应用,大大提升了数据访问的性能。
8)为了避免大buffer_pool的实例重启服务时过长的warmup时间,你可以在重启后立即加载缓存页面。MySQL可以在关闭时导出完全数据文件,检阅此文件找出重启时需要加载的pages。你可以在任何手工导入导出buffer_pool,比如在性能测试时或者在执行复杂的OLAP查询后。
分区的改进(partition)
1)最大分区数量提高到8192,这包括所有的分区和子分区。使用ALTER TABLE … EXCHANGE PARTITION 可以在未分区表和分区表和子分区表之间交换分区。这可以用来导出导入分区。
2)支持显式分区数据查询,例如:
SELECT * FROM employees PARTITION (p0, p2);
DELETE FROM employees PARTITION (p0, p1);
UPDATE employees PARTITION (p0) SET store_id = 2 WHERE fname = ‘Jill’;
SELECT e.id, s.city FROM employees AS e JOIN stores PARTITION (p1) AS s …;
复制和日志(replication)
1)支持延时复制,MySQL现在支持延迟复制,默认是0秒。使用CHANGE MASTER TO参数 MASTER_DELAY 来设置延迟。可以让slave跟master之间控制一个时间间隔,方便特殊情况下的数据恢复。(以前是使用第三方工具可以做到)
2)行级复制功能加强,可以降低磁盘、内存、网络等资源开销(只记录能确定行记录的字段即可)。
3)现在支持多线程复制。如果开启,sql线程作为协调者协调多个工作线程,数量取决于slave_parallel_workers。现在多线程复制以单库为基础,特定库的更新的相对顺序和主库一样。不过,没有必要协调不同库之间的事务。事务可以被分布到每个库,意味着一个复制从库的工作线程可以顺序执行事务而不必等待其它库的更新完成。
4)支持以全局统一事务ID(GTID)为基础的复制。当在主库上提交事务或者被从库应用时,可以定位和追踪每一个事务。GTID复制是全部以事务为基础,使得检查主从一致性变得非常简单。如果所有主库上提交的事务也同样提交到从库上,一致性就得到了保证。
5)支持启用GTID,对运维人员来说应该是一件令人高兴的事情,在配置主从复制,传统的方式里,你需要找到binlog和POS点,然后change master to指向,而不是很有经验的运维,往往会将其找错,造成主从同步复制报错,在mysql5.6里,如果使用了GTIDs,启动一个新的复制从库或切换到一个新的主库,就不必依赖log文件或者pos位。需要知道master的IP、端口,账号密码即可,因为同步复制是自动的,mysql通过内部机制GTID自动找点同步。
6)binlog的读写现在是崩溃安全的,因为只有完整的事件(或者事务)才会被记录和读取。默认会记录事件的大小以及事件本身,使用大小来验证事件被正确记录。你也可以使用参数binlog_checksum设置使用crc32记录事件的校验值。使用参数master_verify_checksum可以让服务读取校验值。slave-sql-verify-checksum参数使从库读relay日志的时候读取校验值。
MySQL支持在表中保存主库连接信息了。使用参数–master-info-repository和 –relay-log-info-repository来设置。设置 –master-info-repository为表,会记录连接信息到slave_master_info表。设置–relay-log-info-repository为表,会记录relay log信息到slave_relay_log_info表。这几个表都是自动建立在mysql系统库。
增强Performance Schema数据库(Mysql performance schema)
1)记录表的输入与输出,操作包括行级访问表和临时表,如insert,upate,delete.
2)表的事件过滤,以库或者表名为基础。
3)线程的事件过滤,更多关于线程的信息被搜集
4)表和索引I/O以及表锁的统计表。
5)记录命令以及命令的阶段。
移除的特性(Removed Features)
以下被参数移除,同时会显示新的参数。
移除–log,换为–general_log 指定是否开启,–general_log_file=file_name 指定文件名。
移除–log-slow-queries和 log_slow_queries,用–slow_query_log 开启慢查询日志,用–slow_query_log_file=file_name 指定文件名。
移除–one-thread ,使用–thread_handling=no-threads 替换。
移除–safe-mode
移除–skip-thread-priority
移除–table-cache,改为table_open_cache
移除–init-rpl-role 和 –rpl-recovery-rank选项和rpl_recovery_rank 系统参数,以及Rpl_status状态值。
移除engine_condition_pushdown,使用engine_condition_pushdown标识optimizer_switch 参数。
移除have_csv, have_innodb, have_ndbcluster, 和 have_partitioning,使用show engines替换。
移除sql_big_tables,使用big_tables。
移除sql_low_priority_updates ,使用low_priority_updates 。
移除 sql_max_join_size,使用 max_join_size 。
移除max_long_data_size,使用max_long_data_size。
移除 FLUSH MASTER 和 FLUSH SLAVE命令,使用RESET MASTER 和 RESET SLAVE 替换。
移除SLAVE START 和 SLAVE STOP命令,使用START SLAVE 和 STOP SLAVE替换。
移除SHOW AUTHORS 和 SHOW CONTRIBUTORS命令。
移除set命令的OPTION and ONE_SHOT修改器。
不允许在存储过程中或者函数参数中或者存储程序本地变量中使用default来指定(如:SET var_name = DEFAULT命令),但可以在指定系统变量时使用default。
MySQL 5.7 新特性
- 引入对 JSON 的支持,JSON 类型和相关函数。
组复制
InnoDB Cluster
多源复制
增强半同步(AFTER_SYNC)
基于WRITESET的并行复制。
在线开启GTID复制。
在线设置复制过滤规则。
在线修改Buffer pool的大小。
在同一长度编码字节内,修改VARCHAR的大小只需修改表的元数据,无需创建临时表。
可设置NUMA架构的内存分配策略(innodb_numa_interleave)。
透明页压缩(Transparent Page Compression)。
UNDO表空间的自动回收。
查询优化器的重构和增强。
可查看当前正在执行的SQL的执行计划(EXPLAIN FOR CONNECTION)。
引入了查询改写插件(Query Rewrite Plugin),可在服务端对查询进行改写。
EXPLAIN FORMAT=JSON会显示成本信息,这样可直观的比较两种执行计划的优劣。
引入了虚拟列,类似于Oracle中的函数索引。
新实例不再默认创建test数据库及匿名用户。
引入ALTER USER命令,可用来修改用户密码,密码的过期策略,及锁定用户等。
mysql.user表中存储密码的字段从password修改为authentication_string。
表空间加密。
优化了Performance Schema,其内存使用减少。
Performance Schema引入了众多instrumentation。常用的有Memory usage instrumentation,可用来查看MySQL的内存使用情况,Metadata Locking Instrumentation,可用来查看MDL的持有情况,Stage Progress instrumentation,可用来查看Online DDL的进度。
同一触发事件(INSERT,DELETE,UPDATE),同一触发时间(BEFORE,AFTER),允许创建多个触发器。在此之前,只允许创建一个触发器。
InnoDB原生支持分区表,在此之前,是通过ha_partition接口来实现的。
分区表支持可传输表空间特性。
集成了SYS数据库,简化了MySQL的管理及异常问题的定位。
原生支持JSON类型,并引入了众多JSON函数。
引入了新的逻辑备份工具-mysqlpump,支持表级别的多线程备份。
引入了新的客户端工具-mysqlsh,其支持三种语言:JavaScript, Python and SQL。两种API:X DevAPI,AdminAPI,其中,前者可将MySQL作为文档型数据库进行操作,后者用于管理InnoDB Cluster。
mysql_install_db被mysqld --initialize代替,用来进行实例的初始化。
原生支持systemd。
引入了super_read_only选项。
可设置SELECT操作的超时时长(max_execution_time)。
可通过SHUTDOWN命令关闭MySQL实例。
引入了innodb_deadlock_detect选项,在高并发场景下,可使用该选项来关闭死锁检测。
引入了Optimizer Hints,可在语句级别控制优化器的行为,如是否开启ICP,MRR等,在此之前,只有Index Hints。
GIS的增强,包括使用Boost.Geometry替代之前的GIS算法,InnoDB开始支持空间索引。
MySQL 8.0 新特性
最重要的是窗口函数和 CTE
- 窗口函数,这个功能补齐了,非常香。
- CTE (Common Table Expressions)
- 递归 SQL
- UTF8 的变更,默认的 UTF8 字符集是 UTF8MB4
- 优化和完善了对 JSON 的支持,最重要的是 JSON Partial Updates,支持对 JSON 的局部更新。
其他MySQL 8.0计划更新的特性包括:
在锁定行方面增加了更多选项,如SKIP LOCKED和NOWAIT两个选项。其中,
SKIP LOCKED允许在操作中不锁定那些需要忽略的行;NOWAIT则在遇到行的锁定的时候马上抛出错误。
MySQL能根据可用内存的总量去伸缩扩展,以更好利用虚拟机的部署。
新增“隐藏索引”的特性,这样索引可以在查询优化器中变为不可见。索引在标记为不可用后,和表的数据更改同步,但是优化器不会使用它们。对于使用隐藏索引的建议,是当不决定某个索引是否需要保留的时候,可以使用。
引入了原生的,基于InnoDB的数据字典。数据字典表位于mysql库中,对用户不可见,同mysql库的其它系统表一样,保存在数据目录下的mysql.ibd文件中。不再置于mysql目录下。
Atomic DDL。
重构了INFORMATION_SCHEMA,其中,部分表已重构为基于数据字典的视图,在此之前,其为临时表。
PERFORMANCE_SCHEMA查询性能提升,其已内置多个索引。
不可见索引(Invisible index)。
降序索引。
直方图。
角色(Role)。
资源组(Resource Groups),可用来控制线程的优先级及其能使用的资源,目前,能被管理的资源只有CPU。
引入了innodb_dedicated_server选项,可基于服务器的内存来动态设置innodb_buffer_pool_size,innodb_log_file_size和innodb_flush_method。
快速加列(ALGORITHM=INSTANT)。
自增主键的持久化。
可持久化全局变量(SET PERSIST)。
默认字符集由latin1修改为utf8mb4。
默认开启UNDO表空间,且支持在线调整数量(innodb_undo_tablespaces)。在MySQL 5.7中,默认不开启,若要开启,只能初始化时设置。
备份锁。
Redo Log的优化,包括允许多个用户线程并发写入log buffer,可动态修改innodb_log_buffer_size的大小。
默认的认证插件由mysql_native_password更改为caching_sha2_password。
默认的内存临时表由MEMORY引擎更改为TempTable引擎,相比于前者,后者支持以变长方式存储VARCHAR,VARBINARY等变长字段。从MySQL 8.0.13开始,TempTable引擎支持BLOB字段。
Grant不再隐式创建用户。
SELECT ... FOR SHARE和SELECT ... FOR UPDATE语句中引入NOWAIT和SKIP LOCKED选项,解决电商场景热点行问题。
正则表达式的增强,新增了4个相关函数,REGEXP_INSTR(),REGEXP_LIKE(),REGEXP_REPLACE(),REGEXP_SUBSTR()。
查询优化器在制定执行计划时,会考虑数据是否在Buffer Pool中。而在此之前,是假设数据都在磁盘中。
ha_partition接口从代码层移除,如果要使用分区表,只能使用InnoDB存储引擎。
引入了更多细粒度的权限来替代SUPER权限,现在授予SUPER权限会提示warning。
GROUP BY语句不再隐式排序。
MySQL 5.7引入的表空间加密特性可对Redo Log和Undo Log进行加密。
information_schema中的innodb_locks和innodb_lock_waits表被移除,取而代之的是performance_schema中的data_locks和data_lock_waits表。
引入performance_schema.variables_info表,记录了参数的来源及修改情况。
增加了对于客户端报错信息的统计(performance_schema.events_errors_summary_xxx)。
可统计查询的响应时间分布(call sys.ps_statement_avg_latency_histogram())。
支持直接修改列名(ALTER TABLE ... RENAME COLUMN old_name TO new_name)。
用户密码可设置重试策略(Reuse Policy)。
移除PASSWORD()函数。这就意味着无法通过“SET PASSWORD ... = PASSWORD('auth_string') ”命令修改用户密码。
代码层移除Query Cache模块,故Query Cache相关的变量和操作均不再支持。
BLOB, TEXT, GEOMETRY和JSON字段允许设置默认值。
可通过RESTART命令重启MySQL实例。
参考资料与拓展阅读
- Old Reliable: A History of MySQL
- O'Reilly, The History of MySQL
- CNET, Oracle tried to buy open-source MySQL
- MySQL 官方文档, MySQL 5.6 Release Notes
- MySQL 官方文档, MySQL 5.7 Release Notes
- MySQL 官方文档, MySQL 8.0 Release Notes