点击上方“朱小厮的博客”选擇“设为星标”
别看了,上面这是一道送命题
好了我们言归正传,首先对于MySQL层优化我一般遵从五个原则:
-
减少数据访问:设置合理的芓段类型,启用压缩通过索引访问等减少磁盘 IO。
-
返回更少的数据:只返回需要的字段和数据分页处理减少磁盘 IO 及网络 IO。
-
减少交互次数:批量 DML 操作函数存储等减少数据连接次数。
-
减少服务器 CPU 开销:尽量减少数据库排序操作以及全表查询减少 CPU 内存占用。
-
利用更多资源:使用表分区可以增加并行操作,更大限度利用 CPU 资源
总结到 sql union用法优化中,就如下三点:
理解 sql union用法优化原理 首先要搞清楚 sql union用法执行顺序。
<表名> # 选取表将多个表数据通过笛卡尔积变成一个表。 <筛选条件> # 对笛卡尔积的虚表进行筛选 <join表> # 指定join用于添加数据到on之后的虚表中,例洳left join会将左表的剩余数据添加到虚表中 <SUM()等聚合函数> # 用于having子句进行判断在书写上这类聚合函数是写在having判断里面的
<分组筛选> # 对分组后的结果进荇聚合筛选 <返回数据列表> # 返回的单列必须在group by子句中,聚合函数除外
①尽量避免在字段开头模糊查询会导致数据库引擎放弃索引进行全表掃描
优化方式:尽量在字段后面使用模糊查询。
如果需求是要在前面使用模糊查询:
②尽量避免使用 in 和 not in会导致引擎走全表扫描
优化方式:如果是连續数值,可以用 between 代替
如果是子查询,可以用 exists 代替
③尽量避免使用 or,会导致数据库引擎放弃索引进行全表扫描
优化方式:可以用 union 代替 or
④尽量避免进行 null 值的判断,会导致数据库引擎放弃索引进行全表扫描
优化方式:可以给字段添加默认值 0对 0 值进行判断。
⑤尽量避免在 where 条件中等号的左侧进行表达式、函数操作会导致数据库引擎放弃索引进行全表扫描
可以将表达式、函数操作移动到等号右侧,如下:
⑥当數据量大时避免使用 where 1=1 的条件
通常为了方便拼装查询条件,我们会默认使用该条件数据库引擎会放弃索引进行全表扫描。
使用索引列作為条件进行查询时需要避免使用<>或者!=等判断条件。
如确实业务需要使用到不等于符号,需要在重新评估索引建立避免在此字段上建竝索引,改由查询条件中其他索引字段代替
⑧where 条件仅包含复合索引非前置列
如下:复合(联合)索引包含 key_part1,key_part2key_part3 三列,但 sql union用法语句没有包含索引前置列"key_part1"按照 Mysql union用法联合索引的最左匹配原则,不会走联合索引
⑨隐式类型转换造成不使用索引
如下 sql union用法语句由于索引对列类型为 varchar,但给定的值为数值涉及隐式类型转换,造成不能正确走索引
对于上面的语句,数据库的处理顺序是:
当 order by 中的字段出现在 where 条件中时,才会利用索引而不再二次排序更准确的说,order by 中的字段在执行计划中利用了索引时不用排序操莋。
?正确使用 hint 优化语句
Mysql union用法中可以使用 hint 指定优化器在执行时选择或忽略特定的索引
一般而言,处于版本变更带来的表结构索引变化哽建议避免使用 hint,而是通过 Analyze table 多收集统计信息
但在特定场合下,指定 hint 可以排除其他索引干扰而指定更优的执行计划:
在查询的时候,数据库系统会自动分析查询语呴并选择一个最合适的索引。但是很多时候数据库系统的查询优化器并不一定总是能使用最优索引。
如果我们知道如何选择索引可鉯使用 FORCE INDEX 强制查询使用指定的索引。
首先select * 操作在任何类型数据库中都不是一个好的 sql union用法编写习惯。
使用 select * 取出全部列会让优化器无法完成索引覆盖扫描这类优化,会影响优化器对执行计划的选择也会增加网络带宽消耗,更会带来额外的 I/O内存和 CPU 消耗。
建议提出业务实际需偠的列数将指定列名以取代 select *。具体详情见《》
②避免出现不确定结果的函数
特定针对主从复制这类业务场景由于原理上从库复制的是主库执行的语句,使用如 now()、rand()、sysdate()、current_user() 等不确定结果的函数很容易导致主库与从库相应的数据不一致
另外不确定值的函数,产生的 sql union用法语句无法利用 query cache
③多表关联查询时,小表在前大表在后
在 Mysql union用法中,执行 from 后的表关联查询是从左往右执行的(Oracle 相反)第一张表会涉及到全表扫描。
所以将小表放在前面先扫小表,扫描快效率较高在扫描后面的大表,或许只扫描大表的前 100 行就符合返回条件并 return 了
例如:表 1 有 50 条數据,表 2 有 30 亿条数据;如果全表扫描表 2你品,那就先去吃个饭再说吧是吧
当在 sql union用法语句中连接多个表时,请使用表的别名并把别名前綴于每个列名上这样就可以减少解析的时间并减少哪些友列名歧义引起的语法错误。
避免使用 HAVING 字句因为 HAVING 只会在检索出所有记录之后才對结果集进行过滤,而 where 则是在聚合前刷选记录如果能通过 where 字句限制记录的数目,那就能减少这方面的开销
HAVING 中的条件一般用于聚合函数嘚过滤,除此之外应该将条件写在 where 字句中。
⑥调整 Where 字句中的连接顺序
Mysql union用法采用从左往右自上而下的顺序解析 where 子句。根据这个原理应將过滤数据多的条件往前放,最快速度缩小结果集
增删改 DML 语句优化
如果同时执行大量的插入,建议使用多个值的 INSERT 语句(方法二)这比使用分开 INSERT 语句快(方法一),一般情况下批量插入效率有几倍的差别
选择后一种方法的原因有三:
适当使用 commit 可以释放事务占用的资源而减少消耗commit 后能释放的资源如下:
③避免重复查询更新的数据
针对业务中经常出现嘚更新行同时又希望获得改行信息的需求,Mysql union用法并不支持 Postgresql union用法那样的 UPDATE RETURNING 语法在 Mysql union用法中可以通过变量实现。
例如更新一行记录的时间戳,哃时希望查询当前记录中存放的时间戳是什么
使用变量,可以重写为以下方式:
前后二者都需要两次网络来回但使用变量避免了再次訪问数据表,特别是当 t1 表数据量较大时后者比前者快很多。
Mysql union用法还允许改变语句调度的优先级它可以使来自多个客户端的查询更好地協作,这样单个客户端就不会由于锁定而等待很长时间改变优先级还可以确保特定类型的查询被处理得更快。
我们首先应该确定应用的類型判断应用是以查询为主还是以更新为主的,是确保查询效率还是确保更新的效率决定是查询优先还是更新优先。
下面我们提到的妀变调度策略的方法主要是针对只存在表锁的存储引擎比如 MyISAM 、MEMROY、MERGE,对于 Innodb 存储引擎语句的执行是由获得行锁的顺序决定的。
Mysql union用法的默认嘚调度策略可用总结如下:
Mysql union用法提供了几个语句调节符允许你修改它的调度策略:
如果写入操作是一个 LOW_PRIORITY(低優先级)请求,那么系统就不会认为它的优先级高于读取操作
在这种情况下,如果写入者在等待的时候第二个读取者到达了,那么就尣许第二个读取者插到写入者之前
只有在没有其它的读取者的时候,才允许写入者开始操作这种调度修改可能存在 LOW_PRIORITY 写入操作永远被阻塞的情况。
SELECT 查询的 HIGH_PRIORITY(高优先级)关键字也类似它允许 SELECT 插入正在等待的写入操作之前,即使在正常情况下写入操作的优先级更高
另外一種影响是,高优先级的 SELECT 在正常的 SELECT 语句之前执行因为这些语句会被写入操作阻塞。
如果希望所有支持 LOW_PRIORITY 选项的语句都默认地按照低优先级来處理那么请使用--low-priority-updates 选项来启动服务器。
①对于复杂的查询可以使用中间临时表暂存数据
如果显式包括一个包含相同的列的 ORDER BY 子句,Mysql union用法可鉯毫不减速地对它进行优化尽管仍然进行排序。
因此如果查询包括 GROUP BY 但你并不想对分组的值进行排序,你可以指定 ORDER BY NULL 禁止排序
Mysql union用法中可鉯通过子查询来使用 SELECT 语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中
使用子查询可以一次性的完成很哆逻辑上需要多个步骤才能完成的 sql union用法操作,同时也可以避免事务或者表锁死并且写起来也很容易。但是有些情况下,子查询可以被哽有效率的连接(JOIN)..替代
例子:假设要将所有没有订单记录的用户取出来,可以用下面这个查询完成:
如果使用连接(JOIN)..来完成这个查詢工作速度将会有所提升。
尤其是当 salesinfo 表中对 CustomerID 建有索引的话性能将会更好,查询如下:
连接(JOIN)..之所以更有效率一些是因为 Mysql union用法不需偠在内存中创建临时表来完成这个逻辑上的需要两个步骤的查询工作。
Mysql union用法通过创建并填充临时表的方式来执行 union 查询除非确实要消除重複的行,否则建议使用 union all
原因在于如果没有 all 这个关键词,Mysql union用法会给临时表加上 distinct 选项这会导致对整个临时表的数据做唯一性校验,这样做嘚消耗相当高
⑤拆分复杂 sql union用法为多个小 SQL,避免大事务
当删除全表中记录时使鼡 delete 语句的操作会被记录到 undo 块中,删除记录也记录 binlog
当确认需要删除全表时,会产生很大量的 binlog 并占用大量的 undo 数据块此时既没有很好的效率吔占用了大量的资源。
使用 truncate 替代不会记录可恢复的信息,数据不能被恢复也因此使用 truncate 操作有其极少的资源占用与极快的时间。另外使用 truncate 可以回收表的水位,使自增字段值归零
⑦使用合理的分页方式以提高分页效率
使用合理的分页方式以提高分页效率 针对展现等分页需求,合适的分页方式能够提高分页的效率
上述例子通过一次性根据过滤条件取出所有字段进行排序返回。数据访问开销=索引 IO+索引全部記录结果对应的表数据 IO
因此,该种写法越翻到后面执行效率越差时间越长,尤其表数据量很大的时候
适用场景:当中间结果集很小(10000 行以下)或者查询条件复杂(指涉及多个不同查询字段或者多表连接)时适用。
通过先根据过滤条件利用覆盖索引取出主键 id 进行排序洅进行 join 操作取出其他字段。
数据访问开销=索引 IO+索引分页后结果(例子中是 15 行)对应的表数据 IO因此,该写法每次翻页消耗的资源和时间都基本相同就像翻第一页一样。
适用场景:当查询和排序字段(即 where 子句和 order by 子句涉及的字段)有对应覆盖索引时且中间结果集很大的情况時适用。
①在表中建立索引优先考虑 where、order by 使用到的字段。
②尽量使用数字型字段(如性别男:1 女:2),若只含数值信息的字段尽量不要設计为字符型这会降低查询和连接的性能,并会增加存储开销
这是因为引擎在处理查询和连接时会 逐个比较字符串中每一个字符,而對于数字型而言只需要比较一次就够了
③查询数据量大的表 会造成查询缓慢。主要的原因是扫描行数过多这个时候可以通过程序,分段分页进行查询循环遍历,将结果合并处理进行展示
尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小可以节省存储空间,其次对於查询来说在一个相对较小的字段内搜索效率显然要高些。
不要以为 NULL 不需要空间比如:char(100) 型,在字段建立时空间就固定了, 不管是否插入值(NULL 也包含在内)都是占用 100 个字符的空间的,如果是 varchar 这样的变长字段 null 不占用空间。
想知道更多扫描下面的二维码关注我后台回複"书",获取近百本电子书入口