MySql性能优化知识整理

人走茶凉 提交于 2019-12-01 21:30:44

一、数据类型

            慷慨是不明智的,举例varchar(5)和varchar(200)存储‘Word’的空间是一样的,那为什么又说慷慨是不明智的呢?实验证明更长的列会消耗更多的内存,因为mysql通常会分配固定大小的内存块来保存内部值。尤其是使用内存临时表进行排序或操作时会特别槽糕。所以最好的策略是只分配真正需要的空间。所以什么数据选择怎样的数据类型也是很重要的。对于钱,提一句,使用int或者bigint进行存储就够了。

二、查询优化

            1.切分查询

            有时候对于一个大查询我们需要“分而治之”,将大查询切分成小查询,每个查询功能完全一样,值完成一小部分,每次只返回一下部分结果。删除旧的数据就是一个很好的列子。定期地清除大量数据时,如果用一个大的语句一次性完成的话,则可能需要一次锁住很多数据,占满整个事务日志,耗尽系统资源,阻塞很多小的但重要的查询。将一个大的delete语句切分多个较小的查询可以尽可能小地影响mysql性能,同时还可以减少mysql复制的延迟。例如:我们需要每个月运行一次下面的查询:

delete from message where create < date_sub(NOW(),INTERVAL 3 MONTH)

那么可以用类似下面的方法来完成:

rows_affected = 0
do {

    rows_affected = do_query(
      "delete from message where create < date_sub(NOW(),INTERVAL 3 MONTH) LIMIT 100000")
}while rows_affected >0

一次删除一万行数据来说是一个比较高效而且对服务器影响也最小的做法。同时,需要注意的是,如果是每次删除操作数据后,都暂停一会儿再做下一次删除,这样也是可以的。

            2.子查询和关联查询

 关联查询:

select distinct id from film inner join actor using(film_id)

子查询:

select id from film where exists(select * from actor where film.id = actor.id);

进行性能对比发现:子查询比关联查询要快些。

       总结: 一是不需要听取那些关于子查询的“绝对真理”,二是应该用测试来验证对子查询的执行计划和响应时间的假设。注意子查询有个bug,下面的写法会锁住table2中的一条记录:

select ... from table1 where col=(select ... from table2 where ...)

如果遇到该bug,子查询在高并发情况下的性能,就会和在单线程测试时的性能相差甚远。

            3.在同一个表上查询和更新

              mysql不允许对同一个表同时进行查询和更新。

            4.优化特定类型的查询

            4.1优化COUNT()查询

            count()是一个特殊的函数,有两种非常不同的作用:它可以统计某个列值的数量,也可以统计行数。在统计列值时要求列值是非空的(不统计null)。如果在count()的括号中指定了列或者列的表达式,则统计的就是这个表达式有值的结果数。

            count()的另一个作用是统计结果集的行数,当mysql确认括号内的表达式不可能为空时,实际上就是在统计行数。最简单的就是当我们使用count(*)的时候,这种情况下通配符*并不会像我们猜想的那样扩展成所有的列,实际上它会忽略所有的列而直接统计所有的行数。

           简单的优化

           我们如何快速查找到所有ID大于5的城市:

select count(*) from city where id >5

           通过结果可以看到该查询需要扫描4097行数据。如果将条件反转一下,先查找ID小于等于5的城市数,然后用总城市数一减就能得到同样的结果,却可以将扫描的行数减少到5行以内。

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

            5.延迟关联

            延迟关联可以优化关联查询中的limit子句:

select id , name from film inner join(select id from film order by  tilte limit 50,5) 
as lim using(id)

         如果知道详细的位置,可以使用下面的:

select  id ,name from film where position between 50 and 54 order by postion;

         假设查询返回的主键为16049 到 16030 的记录,那么下一页就可以从16030这个点开始:

select * from renal where id < 16030 order by id desc limit 20

 

 

 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!