常用SQL优化

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Hzt_fighting_up/article/details/78571885

这里的优化是针对InnoDB存储引擎的
(一)优化大批量插入,针对load
顺序导入(待补充)

(二)优化insert语句
1)如果同时从同一个客户端插入多行,应尽量使用多个值表的insert语句。这种方式将大大缩减客户端与数据库之间的连接、关闭等消耗。例:

insert into test values(1,2),(1,3),(1,4)

我们一般使用ssm框架,在使用mybatis实现批量插入时,已经做了这个优化了,例如:

<insert id="batchInsert" parameterType="java.util.List">
       insert into user(username, password) values
       <foreach collection="list" item="item" index="index"
           separator=",">
           (#{item.username},
           #{item.password} )
       </foreach>
</insert>

2)将索引文件和数据文件分在不同的磁盘上存放(在InnoDB存储引擎下,索引文件和数据文件被存放在.ibd文件中)
3)当从一个文件中装载一个表时,使用load data infile。一般较少碰到这种情况吧

(三)优化order by
order by主要是用来对结果进行一个排序。
mysql中有两种排序方式
1)使用有序索引顺序扫描直接返回有序顺序,不需要额外的排序,操作效率较高
2)FileSort排序:通过对返回数据进行排序。所有不是通过索引直接返回排序结果的排序都是FileSort排序
FileSort并不代表通过磁盘文件进行排序,只是说明进行了一个排序操作,至于是否使用了磁盘文件或临时表,则取决于MySQL服务器对排序参数的设置和需要排序数据的大小
FileSort排序过程。通过相应算法,将取得的数据在sort_buffer_size系统变量设置的内存排序区中进行排序,如果内存装载不下,它就会将磁盘中的数据进行分块,在对各个数据块进行排序,然后各个块合并成一个有序结果集。

如何进行优化:尽量减少额外的排序,通过索引直接返回有序数据
优化方法
1)避免不能使用索引进行排序的情况。只有当索引的顺序和order by子句的顺序完全一致,并且所有列的排序方向都一样(要么都为正序,要么都为反序,如果需要按照不同的方向做排序,可以存储该列值的反传串或者相反数)。如果查询要关联多张表,则只有当order by子句引用的字段全为第一张表时才能使用索引做排序。需要满足最左前缀原则。但是有一种情况可以不满足最左前缀原则,当索引第一列通过where或join被指定了常量时。比如:
数据表rental:

 CREATE TABLE `rental` (
  `rental_id` int(11) NOT NULL AUTO_INCREMENT,
  `rental_date` datetime NOT NULL,
  `inventory_id` mediumint(8) unsigned NOT NULL,
  `customer_id` smallint(5) unsigned NOT NULL,
  `return_date` datetime DEFAULT NULL,
  `staff_id` tinyint(3) unsigned NOT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`rental_id`),
  UNIQUE KEY `idx_rental_date` (`rental_date`,`inventory_id`,`customer_id`) USING BTREE,
  KEY `idx_fk_inventory_id` (`inventory_id`),
  KEY `idx_fk_customer_id` (`customer_id`),
  KEY `idx_fk_staff_id` (`staff_id`),
  CONSTRAINT `fk_rental_customer` FOREIGN KEY (`customer_id`) REFERENCES `customer` (`customer_id`) ON UPDATE CASCADE,
  CONSTRAINT `fk_rental_inventory` FOREIGN KEY (`inventory_id`) REFERENCES `inventory` (`inventory_id`) ON UPDATE CASCADE,
  CONSTRAINT `fk_rental_staff` FOREIGN KEY (`staff_id`) REFERENCES `staff` (`staff_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=16050 DEFAULT CHARSET=utf8

有一个多列索引rental_date
执行下列的语句,仍然使用了索引进行了排序:

mysql> explain select rental_id,staff_id from rental
    -> where rental_date='2005-05-25'
    -> order by inventory_id,customer_id\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: rental
   partitions: NULL
         type: ref
possible_keys: idx_rental_date
          key: idx_rental_date
      key_len: 5
          ref: const
         rows: 1
     filtered: 100.00
        Extra: Using index condition
1 row in set, 1 warning (0.11 sec)

未出现using filesort,说明是通过索引进行排序的

2)优化FileSort算法
一:两次扫描算法,先取出排序字段和行指针信息(第一次),之后在内存排序区中进行排序。如果排序区内存不够,则在零时表中进行排序。完成后根据行指针回表读取记录(第二次扫描)
缺:导致大量随机I/O操作。优:内存开销小
二:一次扫描算法。一次性取出满足条件的行的所有字段,然后在排序区中排序后直接输出结果集。优:效率快。缺:内存开销大
使用哪种算法取决于max_length_for_sort_data和query语句取出的字段总大小。若max_length_for_sort_data大,则使用第二种算法,否则使用第一种算法
注:尽量只使用必要的字段,避免select *选择所有的字段,这样可以减少排序区的使用,提高排序性能。max_length_for_sort_data和sort_buffer_size的值设置要合适,不能太大也不能太小

(四)优化group by
1)即禁止排序。默认情况下mysql会对所有group by col1,col2…的字段进行排序。这与在mysql中指定order by col1,col2…类似。通过order by null 进行优化。因为如果通过FileSort进行排序的话非常耗时
2)建立索引

(五)优化嵌套查询
嵌套查询:通过select语句创建一个单列的查询结果(子查询),然后把这个结果作为过滤条件用在另外一个条件中。可以避免事务或者表死锁。
有些情况下,子查询可以被更有效率的连接(join)替代
连接操作之所以效率要高效一点,是因为mysql不需要在内存中创建临时表来完成逻辑上需要分成多步的查询

(六)优化or条件
前面一篇文章中讲到,如果or前面的列使用了索引,而or后面的列没有使用索引,则这条sql语句不会使用索引。(不会使用索引和其底层有关,执行含有or的sql语句时,其底层通过使用union。将or分成两条sql语句)
如何优化or?为or前后的列都创建索引,利用索引加快查询速度

(五)优化count()
COUNT()函数的作用
1)统计某个列值的数量,统计列值时要求列值是非空的,即如果有列值是null,则其统计结果将会不准确,因为它不会统计进null值
2)统计结果集的行数。当mysql确定括号内的表达式值不可能为空时,实际上统计的就是行数

简单优化
1)反向进行统计
比如:

select count(*) from city where id > 5

优化为:

select (select count(*) from city) - count(*) from city where id < 5

扫描行数将大大减少‘
该优化只针对MIySAM存储引擎。因为MIySAM存储引擎会记录表的行数,而不需要直接去遍历行进行统计
2)使用count计算某个列特定值的行数
比如在同一个查询中统计同一个列的不同值的颜色

select count(color='red'or null) as red,count(color='blue' or null) as blue from items

将不满足条件设置为null,则count将不会统计进来
3)使用近似值。该优化只针对不需要结果精确的情况下进行优化。使用不精确的值可以通过explain获得,explain出来的是优化器估计的行数
个人觉得对于InnoDB存储引擎count()没有什么地方可以优化,其总是要扫描大量的行。

(六)优化关联查询
1):确保ON或USING子句中的列上有索引,并且只需要在关联顺序中的第二个表的相应列上创建索引(是因为关联表中的第一个表不可避免的进行全表扫描码,这里暂时有点疑惑)
2):GROUP BY和ORDER BY中的表达式只涉及到一个表中的列,这样MySQL才有可能使用索引来优化这个过程

参考:《高性能mysql》

猜你喜欢

转载自blog.csdn.net/Hzt_fighting_up/article/details/78571885