高性能MySQL第六章笔记

    xiaoxiao2021-04-18  68

    1.不要查询不需要的列,不要用select *(减少内存占用和网络带宽占用,减少表结构变化带来的影响) 2.EXPLAIN语句结果中的rows是预估的要扫描的行数,Extra:Using Where表示MySQL将通过WHERE条件来筛选存储引擎(注意是存储引擎)返回的记录     一般MySQL能够使用如下三种方式应用WHERE条件,从好到坏:     在索引中使用WHERE条件来过滤,在存储引擎层     使用索引覆盖扫描(在Extra列中出现了Using index)来返回记录,直接从索引中过滤不需要的记录并返回命中的结果。这是在MySQL服务器层返回的,但无须再回表查询记录。     从数据表中返回数据,然后过滤不满足条件的记录(Extra:Using Where)。这是在MySQL服务层完成,MySQL需要从数据表读出记录然后过滤。 3.使用多个简单查询来代替一个复杂查询     3.1如每个月删除旧的数据,为了防止一次锁住很多数据,占满整个事务日志,耗尽系统资源,阻塞很多小的但重要的查询:     将DELETE FROM message WHERE created < DATE_SUB(NOW,INTERVAL 3 MONTH);     换为:     rows_affected = 0     do{         rows_affected = do_query(         "DELETE FROM message WHERE created < DATE_SUB(NOW,INTERVAL 3 MONTH)         LIMIT 10000"         )         }while rows_affected>0          3.2分解关联查询     优势:     让缓存的效率更高;减少锁的竞争;在应用层做关联,可以更容易对数据库进行拆分,更容易做到高性能和可扩展;减少冗余记录的查询,减少内存和网络的消耗。 4.查询执行的基础     内容比较多,这里只记录几点:

        4.1 查询执行路径

        4.2 查询状态:可用SHOW FULL PROCESSLIST命令查看查询状态     4.3 MySQL如何执行关联查询:嵌套循环     4.4 MySQL的临时表是没有索引的,在编写复杂的子查询和关联查询的时候需要注意这一点 5.MySQL查询优化器的缺陷     5.1 避免用IN(子查询)     如SELECT * FROM sakila.film WHERE file_id IN(         SELECT film_id FROM sakila.film_actor WHERE actor_id = 1;         )     我们会认为上面的查询会这样执行:     --SELECT GROUP_CONCAT(film_id) FROM sakila.film_actor WHERE actor_id = 1;     --Result:1,23,25,106,140,166,277,361,436,499,506,509,605,635,749,832,939,970,980     SELECT * FROM sakila.film     WHERE film_id     IN(1,23,25,106,140,166,277,361,436,499,506,509,605,635,749,832,939,970,980)          但MySQL实际会将查询改写成下面这样的关联子查询:     SELECT * FROM sakila.film     WHERE EXISTS(         SELECT * FROM sakila.film_actor WHERE actor_id = 1         AND film_actor.film_id = film.film_id);     性能非常差     可用如下语句改写:     SELECT film.* FROM sakila.film     INNER JOIN sakila.film_actor USING(film_id)     WHERE actor_id = 1;‘     另一个优化的方法是使用GROUP_CONCAT()在IN()中构造一个由逗号分隔的列表     注1:关联子查询:在关联子查询中,对于外部查询返回的每一行数据,内部查询都要执行一次。另外,在关联子查询中是信息流是双向的。外部查询的每行数据传递一个值给子查询,然后子查询为每一行数据执行一次并返回它的记录。然后,外部查询根据返回的记录做出决策。     注2:可用EXPLAIN EXTENDED来查看这个查询被改写成什么样子     注3:前面提到关联子查询效率低,可以用join代替,但其实不是所有关联子查询效率都低,应当测试     注4:可用SHOW STATUS 查看扫描的行数     5.2 如果要取出UNION ALL的两个子句的前N条可以在子句里面和外面都加上LIMIT N;     5.3 MIN()和MAX():     看这个语句:SELECT MIN(actor_id) FROM sakila.actor WHERE first_name = 'PENELOPE';     first_name上没有索引所以会全表扫描,因为主键是按照从小到大排列,理论上扫描到第一个满足条件的记录就是了,可是MySQL却只会全表扫表,重写:     SELECT actor_id FROM sakila.actor USE INDEX(PRIMARY)     WHERE first_name = 'PENELOPE' LIMIT 1; 6. 优化特定类型的查询         6.1 COUNT()或COUNT(*)统计行数,COUNT(exp)统计exp有值的结果数     条件反转优化:     将SELECT COUNT(*) FROM world.City WHERE ID > 5;     优化为:     SELECT (SELECT COUNT(*) FROM world.City)-COUNT(*)     WHERE world.City WHERE ID < 5;     近似值优化,有些业务不需要精确值,可以用EXPLAIN出来的rows近似值代替:          6.2 优化关联查询:     确保ON或者USING子句中的列上有索引     确保GROUP BY和ORDER BY中的表达式只涉及一个表中的列,这样MySQL才能使用索引来优化这个过程          6.3 优化子查询     尽可能使用关联查询代替(MySQL5.6后可忽略这条)          6.4优化LIMIT分页     大偏移量时LIMIT效率很差,因为他会扫描很多然后丢弃他们     SELECR film_id,description FROM sakila.film ORDER BY title LIMIT 50,5     "延迟关联"优化为:     SELECT film.film_id , film.description          FROM sakila.film     INNER JOIN(         SELECT film_id FROM sakila.film         ORDER BY title LIMIT 50,5         )AS lim USING(film_id)     另一种优化是,预先存储排名信息,然后优化为:     SELECT film_id,description FROM sakila.film     WHERE position BETWEEN 50 AND 54 ORDER BY position          6.5 优化UNION查询     MySQL总是通过创建并填充临时表的方式来执行UNION查询,因此很多优化策略在UNION中都没法很好地使用,经常需要手动的将WHERE,LIMIT,ORDER BY等子句“下推”到UNION的各个子查询中,以便优化器利用这些条件进行优化。     除非确实需要消除重复的行,否则就一定要使用UNION ALL,如果没有ALL,MySQL就会给临时表加上DISTINCT选项,代价很高 7.其他注意点:     7.1不要用前置%和前后双%,这会使索引失效     7.2 索引的最左前缀匹配     7.3 使用left join或not exists来优化not in(会使索引失效)     7.4 避免隐式转换,这会使索引失效     7.5 使用in代替or,in可利用索引         7.6 不要join太多表     7.7 程序中使用预编译语句:防止SQL注入;同步地使用执行计划;一次解析,多次利用     7.8 程序连接不同数据库使用不同的帐号,禁止跨库查询:降低业务耦合度;安全;为了以后的分库分表和数据库迁移     7.9 禁止使用不含字段列表的INSERT语句     7.10 减少同数据库的交互次数     7.11 禁止用ORDER BY rand()进行随机排序:这会把表中所有符合条件的数据装载到内存中;推荐在程序中获取随机值到数据库中取相应的数据     7.12 禁止在WHERE中对列进行函数转换和计算,这回导致索引失效    
    转载请注明原文地址: https://ju.6miu.com/read-675212.html

    最新回复(0)