MySQL 数据库 - SQL 优化

一.结构图
MySQL 数据库 - SQL 优化
在这里插入图片描述
1.1ISAM(Indexed Sequential Access Method)
ISAM是一个定义明确且定义明确的数据表格管理方法,在设计时就考虑到数据库的查询次数远远大于更新的次数。因此,ISAM执行读取操作的速度很快,而且不占用大量的内存和存储资源。
ISAM的两个不足点:
1.ISAM不支持事务;
2.不能够容错。如果你的硬盘崩溃了,那么数据文件就无法恢复;
如果你正在把ISAM用在关键的应用程序里面,那么必须经常备份你所有的实时数据,通过其复制特性,MYSQL能够支持这样的备份应用程序

使用 ISAM 注意点:必须经常备份所有实时数据。

1.2MyISAM
MyISAM是MYSQL的ISAM拓展格式数据引擎。除了提供ISAM里面所没有的索引和字段管理的大量功能,MyISAM还使用一种表格锁定的机制,来优化多个并发的读写操作,其代价是要经常运行OPTIMIZE TABLE 命令;来回复被更新机制浪费的空间。MyISAM还有一些有用的拓展,例如用来修复数据库文件的MyISAMCHK 工具和用来恢复浪费空间的 MyISAMPACK 工具。MYISAM 强掉了快速读取操作,这可能就是为什么MYSQL受到WEB开发如此青睐的主要原因:在WEB开发中所进行的大量数据操作都是读取操作。所以,大多数虚拟主机供应商的INTERNET 平台提供商 只允许使用 MYISAM 格式。
MyISAM 格式的一个重要缺陷就是不能在表损坏后恢复数据。
MyISAM引擎使用注意事项:必须经常使用Optimize Table 命令清理空间;必须经常备份所有实时数据。工具有用来工具有用来修复数据库文件的 MyISAMCHK 工具和用来恢复浪费空间的 MyISAMPACK 工具。不支持事务。数据越多,写操作效率越低。因为要维护数据和索引信息。(索引越多,相对效率越低)
如果使用该数据库引擎,会生成三个文件:
.frm:表结构信息
.MYD:数据文件
.MYI:表的索引信息

1.3InnoDB
InnoDB数据库引擎都是早就MYSQL灵活性的技术的直接产品,这些技术就是MYSQL++API。在使用MYSQL的时候,你面对的没一个挑战几乎都源于ISAM和MyISAM数据库引擎不支持事务处理也不支持外键。尽管要比ISAM和MyISAM引擎慢很多,但是InnoDB包括了对事务和外键的支持,这两点都是前两个引擎所没有的。到现在的MYSQL(5.5以上版本)常用版本默认引擎。

InnoDB 给 MySQL 提供了具有提交、回滚和崩 溃恢复能力的事务安全(ACID 兼容)存储引擎。InnoDB 锁定在行级并且也在 SELECT 语句提 供一个 Oracle 风格一致的非锁定读,这些特色增加了多用户部署的性能。没有在 InnoDB 中 扩大锁定的需要,因为在 InnoDB 中行级锁定适合非常小的空间。InnoDB 也支持 FOREIGN KEY 强制。在 SQL 查询中,你可以自由地将 InnoDB 类型的表与其它 MySQL 的表的类型混合起来,甚至在同一个查询中也可以混合。 InnoDB 是为处理巨大数据量时的最大性能设计,它的 CPU 效率可能是任何其它基于 磁盘的关系数据库引擎所不能匹敌的。 InnoDB 存储引擎被完全与 MySQL 服务器整合,InnoDB 存储引擎为在主内存中缓存数据 和索引而维持它自己的缓冲池。InnoDB 存储它的表&索引在一个表空间中,表空间可以包 含数个文件(或原始磁盘分区)。这与 MyISAM 表不同,比如在 MyISAM 表中每个表被存在 分离的文件中。InnoDB 表可以是任何尺寸,即使在文件尺寸被限制为 2GB 的操作系统上。 在 MySQL5.7 版本中,InnoDB 存储引擎管理的数据文件为两个:分别是 frm,idb 文件。
InnoDB 特点:
1)、支持事务
2)、数据多版本读取(InnoDB+MyISAM+ISAM)
3)、锁定机制的改进
4)、实现外键

二.innodb 与 myisam 区别

1.. InnoDB 支持事务,MyISAM 不支持,对于InnoDB每一条SQL语句都默认封装成事务,自动提交
这样会影响速度,所以最好把多条SQL语句放在begin transaction和commit之间组成一个事务
2.. InnoDB 支持外键,而 MyISAM 不支持。对一个包含外键的 InnoDB 表转为 MYISAM  失败;
3.InnoDB是聚集索引,数据文件和索引绑定在一起,必须要有主键,通过主键索引效率很高。但是辅
助索引需要查询两次,先查询主键,然后 通过主键查询到数据。因此,主键不应该过大,因为主键过
大,其他的索引也会很大。
而MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是
独立的
4.InnoDB不保存表的具体行数,执行select * from table需要进行全局扫描;
MyISAM用一个变量保存了整个表的行数,执行上述语句只需读出该变量即可,速度很快
5.. Innodb 不支持全文索引,而 MyISAM 支持全文索引,查询效率上 MyISAM 要高;

2.1如何选择数据库索引
1.是否支持事务?需要选择InnoDB,不需要选择MyISAM;
2.如果表中绝大多数只是读查询,可以考虑MyISAM,如果读写也挺频繁,使用InnoDB;
3.系统崩溃后,MyISAM恢复困难,能否接受;
4.MYSQL5.5版本之后。InnoDB已经成为了mysql的默认引擎,说明优势有目共睹,不知道用那个引擎,那就用InnoDB,至少不会差;

三.MYSQL中索引的简介
3.1索引的优点
为什么要创建索引? 因为创建索引可以大大提高系统的查询性能
第一.创建唯一索引,可以保证数据库表中每一行数据的唯一性;
第二.可以大大加快数据的检索速度,这也是创建索引的主要原因;
第三.可以加快表与表之间的连接,特别是实现数据的参考方面有特别的意义;
第四.在使用分组和排序字句进行数据检索时,可以减少查询中分组和排序的时间;
第五:通过使用索引,可以在查询的过程中,使用查询优化器,提高系统的性能;

3.2索引的缺点
第一:创建索引和维护索引要消耗时间,这种时间随数据量的增加而增加;
第二:索引占用物理空间,除了数据表占据空间外,每个索引还要占用一定的物理空间。如果要简历聚集索引,那么需要的空间更大
第三:对表中的数据进行增加,删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度:

3.3什么样的字段适合创建索引?
第一:在需要搜索的列上,可以加快搜索速度;
第二:在作为主键的列上,强制改列的唯一性和组织表中数据的排列数据;
第三:在经常用在连接的列上,这些列是一些外键,可以加快连接的速度;
第四:在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的
第五:在经常需要排序的列上建立索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
第六:在经常使用WHERE子句中的列上创建索引,加快条件的判断速度;

3.4什么样的字段不适合建立索引?
第一:在查询中很少使用或者列不应该创建索引;
第二;只有很少数据值的列不应该增加索引;
第三:哪些定义text,image,和bit数据类型的列不应该增加索引;
第四:当修改性能远远大于检索性能时,不应该创建索引;

四.MYSQL中的索引种类
4.1 B-Tree索引
B-Tree索引,就是所有的索引节点按照balance tree的数据结构来存储。B-Tree结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度。
B-Tree中,每个节点包含:
1.本节点所含关键字的个数;
2.指向父节点的字数;
3.关键字;
4.指向节点的指针;
对于一棵 m 阶 B-tree,每个结点至多可以拥有 m 个子结点。各结点的关键字和可以拥 有的子结点数都有限制,规定 m 阶 B-tree 中,根结点至少有 2 个子结点,除非根结点为叶 子节点,相应的,根结点中关键字的个数为 1~m-1;非根结点至少有[m/2]([],向上取整) 个子结点,相应的,关键字个数为[m/2]-1~m-1

B-tree有以下特征:
1.关键字集合分布式在整棵树中;
2.任何一个关键字出现且出现在一个节点中;
3.搜索有可能在非叶子节点结束;
4.搜索性能等价于在关键字全集内做一次二分查找;
5.自动层次控制;
由于限制了除根结点以外的非叶子结点,至少含有 M/2 个儿子,确保了结点的至少利 用率,其最低搜索性能为:
在这里插入图片描述
其中,M 为设定的非叶子结点最多子树个数,N 为关键字总数; 所以 B-树的性能总是等价于二分查找(与 M 值无关),也就没有 B 树平衡的问题; 由于 M/2 的限制,在插入结点时,如果结点已满,需要将结点分裂为两个各占 M/2 的 结点;删除结点时,需将两个不足 M/2 的兄弟结点合并。

MYSQL中索引管理
在 MySQL 中,对索引的查看和删除操作是所有索引类型通用的。
1.普通索引
这是最基本的索引,它没有任何限制 MyIASM 中默认的 BTREE 类型的索引,也是我们大 多数情况下用到的索引。
2.唯一索引
与普通索引类似,不同的是:索引列的值必须为一,但允许有空值。如果是组合索引,则值的组合必须唯一,创建方法和普通索引类似;
3.全文索引
MySQL 从 3.23.23 版开始支持全文索引和全文检索,FULLTEXT 索引仅可用于 MyISAM 表;他们可以从 CHAR、VARCHAR 或 TEXT 列中作为 CREATE TABLE 语句的一部分被创建,或 是随后使用 ALTER TABLE 或 CREATE INDEX 被添加。 对于较大的数据集,将你的资料输入一个没有 FULLTEXT 索引的表中,然后创建索引, 其速度比把资料输入现有 FULLTEXT 索引的速度更为快。不过切记对于大容量的数据表,生 成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。
4.组合索引
平时用的 SQL 查询语句一般都有比较多的限制条件,所以为了进一步榨取 MySQL 的效 率,就要考虑建立组合索引。例如上表中针对 title 和 time 建立一个组合索引:ALTER TABLE article ADD INDEX index_title_time (title(50),time(10))。建立这样的组合索引,其实是相当于分 别建立了下面两组组合索引: –title,time –title 为什么没有 time 这样的组合索引呢?这是因为 MySQL 组合索引“最左前缀”的结果。简 单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引,

五.MYSQL中索引的优化
1.索引不会包含有NUll值的列
只要列中包含有NUll值都将不会被包含在索引中,组合索引中只要有一列含有NUll,那么这一列对于此组合索引是无效的。所以我们在数据库设计的时候不要让字段的默认值为NUll;
2.使用短索引
对串列进行索引,如果可以应该指定一个前缀长度。短索引不仅可以提高查询速度还可以节省磁盘空间和I/O操作;
3.索引列排序
MySQL查询只使用一个索引,因此如果where子句中已经使用了该索引,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引;
4.like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,如果使用也是一个问题。like“%aaa%”不会使用索引,而like“aaa%”可以使用索引;
5.不要在列上进行运算
例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导 致 索 引 失 效 而 进 行 全 表 扫 描 , 因 此 我 们 可 以 改 成 : select * from users where adddate<’2007-01-01′

索引总结:
MySQL只对以下操作符才使用索引: < ,<=,=,>=,between,in,以及某些时候的like。而理论上每张表里面最多可创建16个索引,不过除非数据量真的很多,否则过多的使用索引也不是那么好玩的。
建议:一个表的索引数最好不要超过 6 个,若太多则应考虑一些不常使用到的列上建的 索引是否有必要。

六.MySQL中SQL的常见优化策略
1.避免全表扫描
对查询进行优化,避免全局扫描,首先应该考虑在where 和 order 设计的列上建立索引;
2.便面null值判断
尽量避免在where字句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全局扫描;如:
select id from t where num is null 可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询: select id from t where num=0
3.避免等值判断
尽量避免在where子句中使用!= 或者<>,否则引擎将放弃使用索引而进行全扫描;
4.避免使用or逻辑
应该避免在where子句中使用or来连接条件,否则将导致引擎放弃使用索引而进行全局扫描:
select id from t where num=10 or num=20
可以这样查询: select id from t where num=10 union all select id from t where num=20

5.慎用in和not in逻辑
in 和 not in也要慎用,否则会导致全表扫描
select id from t1 where num in(select id from t2 where id > 10)
此时外层查询会全表扫描,不使用索引。
可以修改为:
select id from t1,(select id from t1 where id > 10)t2 where t1.id = t2.id
此时索引被使用,可以明显提升查询效率。

6.注意模糊查询
下面的查询也将导致全表扫描:
select id from t where name like ‘%abc%’ 模糊查询如果是必要条件时;
可以使用 select id from t where name like 'abc%'来实现模
糊查询,此时索引将被使用。如果头匹配是必要逻辑,建议使用全文搜索引擎(Elastic search、 Lucene、Solr 等)。

7.避免查询条件中字段计算
行全表扫描。
如:
select id from t where num/2=100
应改为:
select id from t where num=100*2

8.避免查询条件中对字段进行函数操作
应尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行 全表扫描。如:
select id from t where substring(name,1,3)=‘abc’–name
以 abc 开头的 id 应改为:
select id from t where name like ‘abc%’

9.where子句“=”左边注意点
不要在where字句中的“=”左边进行函数运算,算术运算,或其他表达式运算,否则系统可能无法正确使用索引。

10.组合索引的使用
在使用索引字段作为条件时,该索引是符合索引,那么必须使用到该索引中的第一个字段作为条件才能保证系统使用该索引,否则该索引不会被使用。

11.不要定义无意义的查询
不要写一些没有意义的查询,如需要生成一个空表结构: select col1,col2 into #t from t where 1=0 这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: create table #t(…)

12.exists
很多时候用exists代替in是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)

13.索引也有可能失效
并不是所有索引对查询都有效,SQL 是根据表中数据来进行查询优化的,当索引列有大 量数据重复时,SQL 查询可能不会去利用索引,如一表中有字段 sex,male、female 几乎各 一半,那么即使在 sex 上建了索引也对查询效率起不了作用。

14.表格字段类型选择
尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和 连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每 一个字符,而对于数字型而言只需要比较一次就够了。 尽可能的使用 varchar 代替 char ,因为首先可变长度字段存储空间小,可以节省存储 空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

15.查询语句中的字段
任何地方都不要使用select * from ,用具体的字段代替 * 不要返回用不到的字段

16索引无关优化
不使用*、尽量不使用 union,union all 等关键字、尽量不使用 or 关键字、尽量使用等 值判断。
表连接建议不超过 5 个。如果超过 5 个,则考虑表格的设计。(互联网应用中)
表连接方式使用外联优于内联。
外连接有基础数据存在。如:A left join B,基础数据是 A。
A inner join B,没有基础数据的,先使用笛卡尔积完成全连接,在根据连接条件得到内 连接结果集。
大数据量级的表格做分页查询时,如果页码数量过大,则使用子查询配合完成分页逻辑。
Select * from table limit 1000000, 10
Select * from table where id in (select pk from table limit 100000, 10

17.MySQL+MyCat分库分表
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章