文章目录
- 一、MySQL架构
- 架构图
- 存储引擎
- MyISAM引擎特点
- InnoDB引擎特点
- 管理存储引擎
- 二、性能优化
- 索引
- 索引管理
- EXPLAIN 工具
- 使用profile工具 监控
一、MySQL架构
架构图
存储引擎
MySQL提供了多种存储引擎供用户选择,每种存储引擎都有自己的特点和使用场景。
InnoDB:
- 默认存储引擎,支持事务、行级锁、外键等特性。
- 适合处理大量数据的应用程序,提供高并发性和数据完整性。
MyISAM:
- 早期版本的默认存储引擎,不支持事务和行级锁。
- 适合处理大量只读数据的应用程序,查询速度快。
Memory(HEAP):
- 数据存储在内存中,访问速度快,但是数据不会持久化。
- 适合储存临时数据或者缓存数据。
Archive:
- 专门设计用于存储和检索大量历史数据。
- 数据压缩率高,但是不支持索引和事务。
CSV:
- 将数据以 CSV 格式存储在文件系统中。
- 适合与其他应用程序交换数据。
NDB (Cluster):
- 用于 MySQL 集群环境,提供高可用性和线性扩展性。
- 适合需要高可用性和可伸缩性的应用程序。
在选择存储引擎时,需要根据具体的应用需求,考虑性能、可靠性、可扩展性等因素,选择最合适的存储引擎。一般情况下,InnoDB 是首选,因为它提供了事务支持、外键等特性,并且性能也很优秀。
MyISAM和InnoDB的区别
- storage limits(存储上限): myisam (256t )innodb(64t) 但是mysql 根本达不到这么大的数据量
- transactions(事务): myisam 不支持 innodb 支持
- locking granularity(锁级别): myiasam 表级 innodb 行级
- 提高mvcc(多版本的并发控制) : 提高数据库的并发性
- data caches (数据缓存): myisam 不支持 innodb 支持
MVCC 是 Multiversion Concurrency Control 的缩写,即多版本并发控制。它是 InnoDB 存储引擎实现并发控制和事务隔离级别的一种机制。
MVCC 的工作原理如下:
- 每行数据都会保存两个隐藏的列,分别记录了行的创建时间和行的过期时间(或删除时间)。
- 在读取数据时,MVCC 会根据事务的隔离级别,选择对应版本的数据进行返回。
- 在写入数据时,MVCC 会创建一个新版本的行,并更新行的过期时间。
- 通过维护多个版本的数据,MVCC 可以做到在不加锁的情况下实现非阻塞的并发控制。
MVCC 主要优点如下:
- 读不阻塞写,写不阻塞读,大幅提高了并发性能。
- 实现了可重复读的隔离级别,避免了幻读问题。
- 无需对普通的 SELECT 语句加锁,简化了应用开发。
MyISAM引擎特点
- 不支持事务
- 表级锁定
- 读写相互阻塞,写入不能读,读时不能写
- 只缓存索引
- 不支持外键约束
- 不支持聚簇索引
- 读取数据较快,占用资源较少
- 不支持MVCC(多版本并发控制机制)高并发
- 崩溃恢复性较差
- MySQL5.5.5 前默认的数据库引擎
MyISAM 存储引擎适用场景
- 只读(或者写较少)
- 表较小(可以接受长时间进行修复操作)
MyISAM 引擎文件
- tbl_name.frm 表格式定义
- tbl_name.MYD 数据文件
- tbl_name.MYI 索引文件
InnoDB引擎特点
- 行级锁
- 支持事务,适合处理大量短期事务
- 读写阻塞与事务隔离级别相关
- 可缓存数据和索引
- 支持聚簇索引
- 崩溃恢复性更好
- 支持MVCC高并发
- 从MySQL5.5后支持全文索引
- 从MySQL5.5.5开始为默认的数据库引擎
管理存储引擎
show engines;
查看mysql支持的存储引擎
查看默认的存储引擎
show variables like '%storage_engine%';
修改默认的存储引擎
vim /etc/my.cnf
[mysqld]
default_storage_engine = InnoDB
查看库中所有表使用的存储引擎
show table status from ;
查看库中指定表的存储引擎
show table status like 'tb_name';
show create table tb_name;
设置表的存储引擎:
CREATE TABLE tb_name(... ) ENGINE=InnoDB;
ALTER TABLE tb_name ENGINE=InnoDB;
二、性能优化
索引
索引介绍
索引:是排序的快速查找的特殊数据结构,定义作为查找条件的字段上,又称为键key,索引通过存储引擎实现。
索引的概念
- 索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址(类似于C语言的链表通过指针指向数据记录的内存地址)。
- 使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该行数据对应的物理地址然后访问相应的数据,因此能加快数据库的查询速度。
- 索引就好比是一本书的目录,可以根据目录中的页码快速找到所需的内容。
- 索引是表中一列或者若干列值排序的方法。
- 建立索引的目的是加快对表中记录的查找或排序。
索引的作用优点
- 加快查询速度,提高数据库性能。
- 设置了合适的索引之后,数据库利用各种快速定位技术,能够大大加快查询速度,这是创建索引的最主要的原因。
- 当表很大或查询涉及到多个表时,使用索引可以成千上万倍地提高查询速度。避免排序和使用临时表。
- 可以降低数据库的IO成本(减少io次数),并且索引还可以降低数据库的排序成本。将随机I/O转为顺序I/O。
- 通过创建唯一性索引,可以保证数据表中每一行数据的唯一性。
- 可以加快表与表之间的连接。
- 在使用分组和排序时,可大大减少分组和排序的时间。
- 建立索引在搜索和恢复数据库中的数据时能显著提高性能。
缺点:
占用额外的磁盘空间,影响插入速度。
创建索引的原则依据
索引虽可以提升数据库查询的速度,但并不是任何情况下都适合创建索引。因为索引本身会消耗系统资源,在有索引的情况下,数据库会先进行索引查询,然后定位到具体的数据行,如果索引使用不当,反而会增加数据库的负担。
- 表的主键、外键必须有索引。因为主键具有唯一性,外键关联的是主表的主键,查询时可以快速定位。
- 记录数超过300行的表应该有索引。如果没有索引,每次查询都需要把表遍历一遍,会严重影响数据库的性能。
- 经常与其他表进行连接的表,在连接字段上应该建立索引。
- 唯一性太差的字段不适合建立索引。
- 更新太频繁地字段不适合创建索引。
- 经常出现在 where 子句中的字段,特别是大表的字段,应该建立索引。
- 在经常进行 GROUP BY、ORDER BY 的字段上建立索引;
- 索引应该建在选择性高的字段上。
- 索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引。
索引优化
- 独立地使用列:尽量避免其参与运算,独立的列指索引列不能是表达式的一部分,也不能是函数的参数,在where条件中,始终将索引列单独放在比较符号的一侧,尽量不要在列上进行运算(函数操作和表达式操作)。
- 左前缀索引:构建指定索引字段的左侧的字符数,要通过索引选择性(不重复的索引值和数据表的记录总数的比值)来评估,尽量使用短索引,如果可以,应该制定一个前缀长度。
- 多列索引:AND操作时更适合使用多列索引,而非为每个列创建单独的索引。
- 选择合适的索引列顺序:无排序和分组时,将选择性最高放左侧。
- 只要列中含有NULL值,就最好不要在此列设置索引,复合索引如果有NULL值,此列在使用时也不会使用索引。
- 对于经常在where子句使用的列,最好设置索引。
- 对于有多个列where或者order by子句,应该建立复合索引
- 对于like语句,以 % 或者 _ 开头的不会使用索引,以 % 结尾会使用索引。
- 尽量不要使用not in和<>操作,虽然可能使用索引,但性能不高
- 不要使用RLIKE正则表达式会导致索引失效
- 查询时,能不要就不用,尽量写全字段名,比如:select id,name,age from students;
- 大部分情况连接效率远大于子查询。
- 在有大量记录的表分页时使用limit。
- 对于经常使用的查询,可以开启查询缓存。
- 多使用explain和profile分析查询语句。
- 查看慢查询日志,找出执行时间长的sql语句优化。
索引类型:
- B+ TREE、HASH、R TREE、FULL TEXT
- 聚簇(集)索引、非聚簇索引:数据和索引是否存储在一起
- 主键索引、二级(辅助)索引
- 稠密索引、稀疏索引:是否索引了每一个数据项
- 简单索引、组合索引: 是否是多个字段的索引
- 左前缀索引:取前面的字符做索引
- 覆盖索引:从索引中即可取出要查询的数据,性能高
索引结构
参考链接 : https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
二叉树
链接: https://www.cs.usfca.edu/~galles/visualization/BST.html
红黑树
参考链接:https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
B-Tree 索引
参考链接: https://www.cs.usfca.edu/~galles/visualization/BTree.html
缺点:
1.连续范围查找都要从头开始,效率不稳定,快的很快,慢的就比较慢。
2.所存数据量越大,查找次数越多。既要存索引也要存数据。
B+Tree索引
参考链接: https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
B+Tree索引:按顺序存储,每一个叶子节点到根结点的距离是相同的;左前缀索引,适合查询范围类的数据。
索引管理
查看索引
show index from 表名;
show keys from 表名;
建立索引
格式
CREATE INDEX 索引名 ON 表名 (列名[(length)]);
create index idx_name on students(name(5));
再查看就多了条索引。
explain select * from students where name='xu xian';
可以看到已经使用了索引。
删除索引
DROP INDEX 索引名 ON 表名;
EXPLAIN 工具
通过EXPLAIN来分析索引的有效性,获取查询执行计划信息,用来查看查询优化器如何执行查询。
参考资料: https://dev.mysql.com/doc/refman/5.7/en/explain-output.html
语法:
EXPLAIN SELECT clause
explain select * from students where name='xu xian';
列名 | 说明 |
---|---|
id | 执行编号,标识select所属的行。如果在语句中没子查询或关联查询,只有唯一的select,每行都将显示1。否则,内层的select语句一般会顺序编号,对应于其在原始语句中的位置 |
select_type | 简单查询:SIMPLE|复杂查询:PRIMARY(最外面的SELECT)、DERIVED(用于FROM中的子查询)、UNION(UNION语句的第一个之后的SELECT语句)、UNIONRESUlT(匿名临时表)、SUBQUERY(简单子查询) |
table | 访问引用哪个表(引用某个查询,如“derived3”) |
type | 关联类型或访问类型,即MySQL决定的如何去查询表中的行的方式 |
possible_keys | 查询可能会用到的索引 |
key | 显示mysql决定采用哪个索引来优化查询 |
key_len | 显示mysql在索引里使用的字节数 |
ref | 当使用索引列等值查询时,与索引列进行等值匹配的对象信息 |
rows | 为了找到所需的行而需要读取的行数,估算值,不精确。通过把所有rows列值 |
Extra | 额外信息 Using index:MySQL将会使用覆盖索引,以避免访问表 Using where:MySQL服务器将在存储引擎检索后,再进行一次过滤 Using temporary:MySQL对结果排序时会使用临时表 Using filesort:对结果使用一个外部索引排序 |
说明: type显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:NULL> system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery >range > index > ALL ,一般来说,得保证查询至少达到range级别,最好能达到ref。
类型 | 说明 |
---|---|
All | 最坏的情况,全表扫描 |
index | 和全表扫描一样。只是扫描表的时候按照索引次序进行而不是行。主要优点就是避免了排序, 但是开销仍然非常大。如在Extra列看到Using index,说明正在使用覆盖索引,扫描索引的数据,它比按索引次序全表扫描的开销要小很多 |
range | 范围扫描,一个有限制的索引扫描。key 列显示使用了哪个索引。当使用=、 <>、>、>=、<、<=、IS NULL、<=>、BETWEEN 或者 IN 操作符,用常量比较关键字列时,可以使用 range |
ref | 一种索引访问,它返回所有匹配某个单个值的行。此类索引访问只有当使用非唯一性索引或唯一性索引非唯一性前缀时才会发生。这个类型跟eq_ref不同的是,它用在关联操作只使用了索引的最左前缀,或者索引不是UNIQUE和PRIMARY KEY。ref可以用于使用=或<=>操作符的带索引的列。 |
eq_ref | 最多只返回一条符合条件的记录。使用唯一性索引或主键查找时会发生 (高效) |
const | 当确定最多只会有一行匹配的时候,MySQL优化器会在查询前读取它而且只读取一次,因此非常快。当主键放入where子句时,mysql把这个查询转为一个常量(高效) |
system | 这是const连接类型的一种特例,表仅有一行满足条件。 |
Null | 意味着mysql能在优化阶段分解查询语句,在执行阶段甚至用不到访问表或索引(高效) |
使用profile工具 监控
set profiling = ON;
打开后,会显示语句执行详细的过程
show profiles ;
查看语句,注意结果中的query_id值
show profile for query 1;
"show profile" 表示要查看或显示一个查询的性能分析信息。
"for query 1" 表示要查看的是第 1 个查询的性能分析信息。