MySQL 常用优化方式
- sql 书写顺序与执行顺序
- SQL设计优化
- 使用索引
- 避免索引失效
- 分析慢查询
- 合理使用子查询和临时表
- 列相关使用
 
- 日常SQL优化场景
- limit语句
- 隐式类型转换
- 嵌套子查询
- 混合排序
- 查询重写
 
 
sql 书写顺序与执行顺序

(7) SELECT
(8) DISTINCT <select_list>
(1) FROM  <main_table>
(3) <join_type> JOIN <join_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) HAVING <having_condition>
(9) ORDER BY <order_by_condition>
(10) LIMIT <limit_number>
SQL设计优化
使用索引
- 确保对经常作为查询条件的列创建索引
- 对JOIN的列创建索引
- 但要注意不要过度索引,因为这会减慢写操作(如INSERT、UPDATE、DELETE)。
避免索引失效
- 匹配前缀:如果在WHERE子句中使用LIKE操作符,且匹配模式的开始部分是通配符(例如LIKE ‘%xyz’),将不会使用索引。但如果是’xyz%',则使用索引。
- 使用函数或表达式:在列上使用函数或表达式(例如WHERE YEAR(column) = 2021)会导致索引失效,因为MySQL无法利用索引直接定位数据
- OR条件:or表达式两边都必须有索引才会走索引,否则将不会走索引。
  
- 反向条件不走索引 != 、 <> 、 NOT IN、IS NOT NULL
- 数据类型不一致,隐式转换(可能)导致索引失效【这点在隐式类型转换中有场景演示】
  
分析慢查询
- 使用EXPLAIN关键字可以帮助你分析SQL查询的执行计划。通过分析,你可以发现潜在的性能瓶颈,如全表扫描、没有使用索引等问题。
合理使用子查询和临时表
- 子查询和临时表如果不当使用,会造成性能问题。在可能的情况下,尝试使用JOIN来替代它们。
列相关使用
-  使用最适合数据的最小数据类型,如INT、VARCHAR等,这可以减少磁盘IO,提高查询效率。 
-  尽量避免使用 SELECT *,而是明确指定需要查询的字段。这不仅可以减少数据传输量,还能提高查询效率。
日常SQL优化场景
limit语句
SELECT *
FROM   operation
WHERE  type = 'SQLStats'
       AND name = 'SlowLog'
ORDER  BY create_time
LIMIT  1000, 10;
在优化上面SQL时,如果数据量特别庞大,除了在type, name, create_time 字段上加组合索引,还可以记录上一次返回列表最后一条数据,以它为开始,优化后(并不会根据数据量的增长而发生变化):
SELECT   *
FROM     operation
WHERE    type = 'SQLStats'
AND      name = 'SlowLog'
AND      create_time > '2017-03-16 14:00:00'
ORDER BY create_time limit 10;
隐式类型转换
隐式转换,就是不带转换类型的转换,当一个字段类型为varchar,但是在判断时SQL是用int去判断,MySQL 就会对这个int进行隐式转换,将其int类型转换为varchar
-- salecode 为varchar类型  
explain select * from my_distribute where salecode=898

 在上述例子中,salecode为varchar类型,其列有索引,但是SQL并没有使用索引,是因为SQL中发生了隐式转换,导致了全表扫描,那是不是所有隐式转换都会使索引失效?
-- address 为int类型  
explain select * from my_distribute where address='22'

 还是同一个表,address类型为int,其列有索引,但是SQL却使用索引[address],以上可知,隐式转换不一定会导致索引失效,而是根据索引的类型变化,如果是数值类型,则右边无论是数值还是字符串都可以走索引,但是我们在开发中,一定要格外注意,避免隐式转换索引失效
嵌套子查询
UPDATE operation o
SET    status = 'applying'
WHERE  o.id IN (SELECT id
                FROM   (SELECT o.id,
                               o.status
                        FROM   operation o
                        WHERE  o.group = 123
                               AND o.status NOT IN ( 'done' )
                        ORDER  BY o.parent,
                                  o.id
                        LIMIT  1) t
                 );

 上述例子中,更新operation使用了子查询去做过滤,并且使用了in条件,子查询将会在检索operation每一条数据时,都会执行一遍子查询,并将结果集返回判断operation的o.id是否在结果集中,效率非常低下,我们在开发中,也尽量使用join去替代子查询,改良后的sql:
UPDATE operation o
       JOIN  (SELECT o.id,
                            o.status
                     FROM   operation o
                     WHERE  o.group = 123
                            AND o.status NOT IN ( 'done' )
                     ORDER  BY o.parent,
                               o.id
                     LIMIT  1) t
         ON o.id = t.id
SET    status = 'applying'

混合排序
MySQL 不能利用索引进行混合排序。但在某些场景,还是有机会使用特殊方法提升性能的。
SELECT *
FROM   my_order o
INNER JOIN my_appraise a ON a.orderid = o.id
ORDER  BY a.is_reply ASC,
          a.appraise_time DESC
LIMIT  0, 20

 由于 is_reply 只有0和1两种状态,可以按照下面的方法重写:
SELECT *
FROM   ((SELECT *
         FROM   my_order o
                INNER JOIN my_appraise a
                        ON a.orderid = o.id
                           AND is_reply = 0
         ORDER  BY appraise_time DESC
         LIMIT  0, 20)
        UNION ALL
        (SELECT *
         FROM   my_order o
                INNER JOIN my_appraise a
                        ON a.orderid = o.id
                           AND is_reply = 1
         ORDER  BY appraise_time DESC
         LIMIT  0, 20)) t
ORDER  BY  is_reply ASC,
          appraisetime DESC
LIMIT  20;
使用表子查询,将两个查询结果集UNION ALL 合并结果实现排序
查询重写
 SELECT
	a.*,
	c.allocated 
FROM
	(
		SELECT resourceid 
		FROM my_distribute d 
		WHERE isdelete = 0 AND cusmanagercode = '22353' 
		ORDER BY salecode LIMIT 20 
	) a
	LEFT JOIN ( 
		SELECT resourcesid, sum( ifnull( allocated, 0 )* 12345 ) allocated 
		FROM my_resources GROUP BY resourcesid 
	) c 
	ON a.resourceid = c.resourcesid

 以上SQL中因为c表使用了全表聚合,导致了数据全表扫描10w数据,优化后:
SELECT
	r.resourcesid,
	sum( ifnull( allocated, 0 ) * 12345 ) allocated 
FROM
	my_resources r,
	( 
		SELECT resourceid, cusmanagercode 
		FROM my_distribute d 
		WHERE isdelete = 0 AND cusmanagercode = '22353' 
		ORDER BY salecode LIMIT 20 
	) a 
WHERE
	r.resourcesid = a.resourceid 
GROUP BY
	resourceid					







![[c++] c++ 中的顺序(构造,析构,初始化列表,继承)](https://img-blog.csdnimg.cn/direct/839bf38b9a014664b66372bed6ef34a6.png)












