数据库优化
程序员文章站
2022-03-03 20:04:01
...
转载请注明出处https://blog.csdn.net/weixin_45163516
数据库优化
优化基本手段
- 说明:计算机性能的瓶颈通常在于磁盘的IO
- 手段:
- 进行架构调整
- 进行硬件提升
- 减少磁盘的IO
- 优化SQL语句
- 数据库的设计
数据库的设计
-
存储引擎的选择
- 根据需要选择合适的存储引擎,见文档
01-数据库存储引擎.md
- 根据需要选择合适的存储引擎,见文档
-
数据表的设计
- 说明:前人总结出来的数据库设计的规范称为范式,主要有三范式。
- 第一范式:表的所有字段都是不可再分割的,称为满足第一范式,记为
1NF
优化前: 用户ID 用户名 手机号 地址 优化后: 用户ID 用户名 手机号 省份 城市 详细地址
- 第二范式:表的字段之间没有部分依赖时,称为满足第二范式,记为
2NF
优化前: 学号 姓名 年龄 课程号 课程名称 课程分数 优化后: 学号 姓名 年龄 课程号 课程名称 学号 课程号 课程分数
- 第三范式:表的字段之间没有传递依赖时,称为满足第三范式,记为
3NF
优化前: 学号 姓名 年龄 性别 所在院校 院校地址 院校电话 优化后: 学号 姓名 年龄 性别 院校代号 院校代号 院校名称 院校地址 院校电话
- 总结:有时我们会根据业务的需要进行反范式设计,通过适当的冗余以减少关联查询。
-
使用字段索引
- 根据需要添加合适的字段索引,见文档
02-数据库索引优化.md
- 根据需要添加合适的字段索引,见文档
优化SQL语句
-
慢查询
- 说明:慢查询时MySQL自带的功能,默认时关闭,开启后会记录执行较慢的SQL语句
- 使用:
查看慢查询时间:show variables like 'long_query_time' 默认是10s,设置为0表示记录所有SQL语句(设置后在新的客户端才能看到) 查看慢查询状态:show variables like 'slow_query%' slow_query_log 是否开启慢查询,默认OFF表示关闭,ON表示开启 slow_query_log_file 执行较慢的SQL语句保存的文件 开启慢查询:set global slow_query_log=ON 是否记录没有使用索引的语句:show variables like 'log_queries_not_using_indexes' 默认为OFF表示关闭,OF表示开启
- 作用:定位耗时的SQL语句。
-
explain
- 说明:查询执行计划,可以看到语句的执行情况
- 示例:
explain select * from star where id > 3\G;
- 选项说明:
select_type:表示SELECT的类型,常见的取值有SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(子查询中的第一个SELECT)等。 table:输出结果集的表。 type:ALL代表全表扫描,通常是不好的,其他的如index/range/const/ref/system则是较好的 type=ALL,全表扫描,MySQL遍历全表来找到匹配的行 type=index,索引全扫描,MySQL遍历整个索引来查询匹配的行 type=range,索引范围扫描,常见于<、<=、>、>=、between等操作符 type=ref,使用非唯一索引扫描或唯一索引的前缀扫描,返回匹配某个单独值的记录行 type=eq_ref,类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配;简单来说,就是多表连接中使用 primary key或者 unique index作为关联条件。 type=const/system,单表中最多有一个匹配行,查询起来非常迅速,所以这个匹配行中的其他列的值可以被优化器在当前查询中当作常量来处理,例如,根据主键 primary key或者唯一索引 unique index进行的查询。 type=NULL,MySQL不用访问表或者索引,直接就能够得到结果 possible_keys:可能被用到的索引 key:查询过程中实际用到的索引,当为null时表示没有使用索引,通常不好 key_len:索引字段最大可能使用的长度,也叫作索引基数,索引基数越大, 表明可能查询的行数越多,效率越低 rows:mysql估计的需要扫描的行数,行数越多,效率越低 这一列只有在EXPLAIN EXTENDED语句中才会出现。 filtered:返回结果的行占需要读到的行(rows列的值)的百分比 extra:显示上述信息之外的其它信息,其主要有以下返回结果 Usingindex 表明此查询使用了覆盖索引(CoveringIndex),即通过索引就能返回结果,无需访问表。 若没显示"Usingindex"表示读取了表数据。 Using index condition 可能会使用索引, Using index就是一定使用索引,这种索引成为覆盖索引,Using index condition则是在必要的时候才使用索引 Using where 表示 MySQL 服务器先读取整行数据,再检查此行是否符合 where 句的条件,符合就留下,不符合便丢弃。效率较慢。 Using filesort 表示Mysql会按查询所需的顺序对结果进行排序,这时就会出现 Using filesort 。排序自然会增加查询时间,导致效率变慢。 解决方法是利用索引进行排序。若查询所需的排序与使用的索引的排序一致,因为索引是已排序的,因此按索引的顺序读取结果返回,此时就不会出现Using filesort。
-
优化示例:
1.尽量不要使用 select *,需要什么字段查询什么字段 2.需要多少数据取多少数据,不要多取一条,使用limit 1限制一条 3.尽量避免复杂的join或子查询 4.禁止结果集自动排序:分组后的结果集会自动排序order by null可以阻止其自动排序 explain select province from star group by province order by null\G; 5.分页时的limit优化 select * from star order by id limit 9999, 10; 这种方式几乎相当于进行全表扫描,可以记录上次查询的最大id为max_id select * from star where id>max_id order by id limit 10; 6.使用连接代替子查询 子查询:select username from user where gid in (select id from goods); 连接:select username from user left join goods on user.gid=goods.id; 说明:左连接效率最高
减少磁盘的IO
-
说明:简单理解就是使用缓存技术代替或减少数据库的读写
-
原理:
请求到来,先检查缓存中是否有相关数据,有缓存数据直接返回。 若没有缓存数据,则从数据库中读取,然后保存到缓存中再返回数据。
进行硬件提升
- 说明:当资源的使用效率足够高,依然不能满足需求,可以提升硬件配置
- 配置:CPU、磁盘、内存、带宽等
进行架构调整
- 单台服务器架构:见图片
单台服务器结构.jpg
- 数据库读写分离:见图片
数据库读写分离.jpg
- 高可用负载均衡:见图片
高可用负载均衡.jpg
MyISAM和InnoDB的区别
存储结构
MyISAM:每个MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,
扩展名指出文件类型。.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。
索引文件的扩展名是.MYI (MYIndex)。
InnoDB:所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),
InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。存储为两个文件 .frm .ibd
存储空间
MyISAM:可被压缩,存储空间较小。支持三种不同的存储格式:动态表、压缩表、
静态表(默认,但是注意数据末尾不能有空格,会被去掉)。
InnoDB:需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。
可移植性、备份及恢复
MyISAM:数据是以文件的形式存储,所以在跨平台的数据转移中会很方便。
在备份和恢复时可单独针对某个表进行操作。
InnoDB:免费的方案可以是拷贝数据文件、备份binlog,或者用mysqldump,
在数据量达到几十G的时候就相对痛苦了。
事务支持
MyISAM:强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。
InnoDB:提供事务支持事务,具有事务(commit)、回滚(rollback)和崩溃修复能力(crash
recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
AUTO_INCREMENT
MyISAM:可以和其他字段一起建立联合索引。引擎的自动增长列必须是索引,如果是组合索引,
自动增长可以不是第一列,他可以根据前面几列进行排序后递增。
InnoDB:InnoDB中必须包含只有该字段的索引。引擎的自动增长列必须是索引,
如果是组合索引也必须是组合索引的第一列。
表锁差异
MyISAM:只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句时,
都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。
InnoDB:支持事务和行级锁,是innodb的最大特色。行锁大幅度提高了多用户并发操作的新能。
但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。
全文索引
MyISAM:支持 FULLTEXT类型的全文索引
InnoDB:不支持FULLTEXT类型的全文索引
表主键
MyISAM:允许没有任何索引和主键的表存在,索引都是保存行的地址。
InnoDB:如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键(用户不可见),
数据是主索引的一部分,附加索引保存的是主索引的值。
表的具体行数
MyISAM:保存表的总行数,如果select count(*) from table;会直接取出出该值。
InnoDB:没有保存表的总行数,如果使用select count(*) from table;就会遍历整个表,
消耗相当大,但是在加了wehre条件后,myisam和innodb处理的方式都一样。
CURD操作
MyISAM:如果执行大量的SELECT,MyISAM是更好的选择。
InnoDB:如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。
DELETE 从性能上InnoDB更优,但DELETE FROM table时,InnoDB不会重新建立表,
而是一行一行的删除,在innodb上如果要清空保存有大量数据的表,
最好使用truncate table这个命令。
外键支持
MyISAM:不支持,InnoDB:支持
如何选择存储引擎?
MyISAM:默认的MySQL插件式存储引擎。如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那么选择这个存储引擎是非常适合的。MyISAM是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。
InnoDB:用于事务处理应用程序,支持外键。如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询以外,还包括很多的更新、删除操作,那么InnoDB存储引擎应该是比较合适的选择。InnoDB存储引擎除了有效地降低由于删除和更新导致的锁定,还可以确保事务的完整提交(Commit)和回滚(Rollback),对于类似计费系统或者财务系统等对数据准确性要求比较高的系统,InnoDB都是合适的选择。
MEMORY:将所有数据保存在 RAM 中,在需要快速定位记录和其他类似数据的环境下,可提供极快的访问。MEMORY 的缺陷是对表的大小有限制,太大的表无法缓存在内存中,其次是要确保表的数据可以恢复,数据库异常终止后表中的数据是可以恢复的。MEMORY表通常用于更新不太频繁的小表,用以快速得到访问结果。
数据库索引优化
索引
索引的原理是利用特殊的查找算法(如二叉树算法),限制访问的行数,提高访问效率。
索引的分类:
主键索引、普通索引、唯一索引、外键索引和全文索引。
文件:
针对于mysql来说
innodb:两个文件 .frm(表结构) .ibd(索引文件)
myisam:三个文件 .frm(表结构) .MYD(表数据) .MYI(表索引)
主键索引
当一张表,把某个列设为主键的时候,则该列就是主键索引
普通索引
一般来说,普通索引的创建,是先创建表,然后在创建普通索引
唯一索引
当表的某列被指定为unique约束时,这列就是一个唯一索引
unique字段可以为NULL,并可以有多NULL,即Null!=Null。但是如果是具体内容,则不能重复
外键索引
维护表的关联关系
id name pwd nich
uid email phone dizhi
全文索引
全文索引,只对MyISAM引擎有用。主要是针对文件,文本的检索, 比如文章或者段落,
它会把某个数据表的某个数据列出现过的所有单词生成一份清单 【注】mysql自己提供的fulltext针对英文生效,想要搜索中文需要使用专门的全文检索引擎或者使用加强版的模糊查询。
【注】全文索引不完全等同于模糊查询比如title字段有这么个数据’abcd20088ccaa’,
使用模糊查询select * from articles where title like’%2008%’可以查找到,而使用全文检索select * from articles where match(title) against(‘2008’);是检索不到的,因为2008不是一个单词!
索引的添加、删除、查看
创建索引
1、ALTER TABLE方法
ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY KEY索引。
ALTER TABLE table_name ADD INDEX index_name (column_list)
ALTER TABLE table_name ADD UNIQUE (column_list)
ALTER TABLE table_name ADD PRIMARY KEY (column_list)
2、CREATE INDEX
CREATE INDEX可对表增加普通索引或UNIQUE索引。
CREATE INDEX index_name ON table_name (column_list)
CREATE UNIQUE INDEX index_name ON table_name (column_list)
删除索引
可利用ALTER TABLE或DROP INDEX语句来删除索引。
DROP INDEX index_name ON talbe_name
ALTER TABLE table_name DROP INDEX index_name
ALTER TABLE table_name DROP PRIMARY KEY //只能删除主键索引
查看索引
show index from 表名\G
Table:表的名称。
Non_unique:如果索引不能包括重复词,则为0。如果可以,则为1。
Key_name:索引的名称。
Seq_in_index:索引中的列***,从1开始。
Column_name:列名称。
Collation:列以什么方式存储在索引中。在MySQL中,有值'A'(升序)或NULL(无分类)。
Cardinality:索引中唯一值的数目的估计值,基数越大,联合查询时使用的概率越大
Sub_part:如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL。
Packet:关键词如何被压缩,如果没有被压缩,则为NULL
Null:如果列含有NULL,则含有YES,如果没有,则该列为NO
Index_type:通过的索引方法,如:BTREE、FULLTEXT、HASH、RTREE
Comment:注释
Index_comment:索引注释
全文索引
创建表时添加
CREATE TABLE articles (
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(200),
body TEXT,
FULLTEXT (title,body)
)engine=myisam charset=utf8;
创建表后添加
ALTER TABLE articles ADD FULLTEXT (title,body);
全文索引的用法
select * from articles where match(title,body) against('要搜索的单词');
索引的代价
SQL语言共分为四大类:数据查询语言DQL,数据管理语言DML(增删改),数据定义语言DDL(create),数据控制语言DCL(grant,commit,rollback)。
1、占用磁盘空间
索引是有开销的,表现在添加索引后.ibd文件(innodb引擎)或者.myi文件(myisam引擎)会变大。
2、导致dml操作速度变慢
添加索引后之所以会快,是因为表依据索引对数据按某种算法(二叉树等)进行排序,所以删除、增加、插入后二叉树要重新排序,导致执行效率降低。
此时要看自己的数据库是dml语句执行的多还是dql语句执行的多
使用以下语句可以查询
show status like 'com_select';
show status like 'com_insert';
show status like 'com_delete';
show status like 'com_update';
一般来说,DQL语句操作比DML语句要多得多!接近9:1
什么情况不使用索引
1、数据唯一性差的字段不要使用索引
比如性别,只有两种可能数据
2、频繁更新的字段不要使用索引
比如登录次数,频繁变化导致索引也频繁变化,增大数据库工作量,降低效率。
3、字段不在where语句出现时不要添加索引
只有在where语句出现,MySQL才会去使用索引
4、数据量少的表不要使用索引
使用了没显著效果
添加了索引但是没有被使用
1、多列索引查询条件没有使用最左边的字段,
id, name, email
在SQL语句中只要没有使用最左边的字段,就不会使用索引
2、如果条件中有or
只要条件中有一个字段没有添加索引,则不会使用索引
3、类型不对应
比方说,如果列类型是字符串,那一定要在条件中将数据使用引号引用起来。否则不使用索引
4、MySQL优化器的决定
如果mysql估计使用全表扫描要比使用索引快,则不使用索引
5、like '%aaa'不会使用到索引
只要模糊查询的模糊值在字符串前面,则不会使用索引
解决like不使用索引的方法
1、Select主键
只要Select的字段刚好是主键,那么就会使用到索引(只对innodb数据库有效)
可以采用分步查询的方法,先select主键再利用主键去找其他字段。不过好像比较麻烦
2、覆盖索引法
覆盖索引是一种特殊的多列索引,当多列索引指向一个查询语句中所有的字段时,该多列索引就被称为覆盖索引。
create index index_name_age on user(name,age); 创建覆盖索引
explain select name,age from user where name like '_1'\G
这时候发现使用索引了
【注】当覆盖索引指向的字段是varchar(380)及380以上的字段时,覆盖索引会失效!
%:表示任意多个字符
_:表示一个字符,常用于限制长度
escape:如果我就真的要查%或者_,怎么办呢?使用escape指定转义字符,默认为\,
如:select name from user where name like '%xiao/_%' escape '/';
3、全文索引法
此方法有较大局限。
全文索引,只对MyISAM引擎有用。主要是针对对文件,文本的检索,比如文章或者段落
它会把某个数据表的某个数据列出现过的所有单词生成一份清单
少于3个字符的单词不会被包含在全文索引里,可以通过修改my.cnf修改选项
ft_min_word_len=3
但是!
全文索引不完全等同于模糊查询
比如title字段有这么个数据’abcd20088ccaa’,使用模糊查询select * from articles wheretitle like’%2008%’可以查找到,而使用全文检索select * from articles where match(title) against(‘2008’);是检索不到的,因为2008不是一个单词!
4、使用全文检索引擎工具包
采用专门的全文检索开源工具可以检索某段字符串。
上一篇: MySQL数据库优化总结