优化顺序:硬件>系统配置>数据库表结构>SQL 及索引。
前3点的优化就不多说了,当数据量超过250万的时候,我们一定要考虑分表分库,这里就不多说了,我们重点看一下sql优化,如果sql没有空间去优化,那就争取征服产品去优化业务;
sql优化注意以下三点:
- 最大化利用索引。
- 尽可能避免全表扫描。
- 减少无效数据的查询。
sql细节
1.假设我们有三张表t_user用户表,t_user_guide用户导购表,t_order订单表,sql语句如下
SELECT
o.fid
FROM
t_user u
LEFT JOIN t_order o ON o.fuser_account_id = u.fuser_id
LEFT JOIN t_user_guide g ON g.fuser_id = u.fuser_id
WHERE
g.fguide_id = 29
疑点:t_user和t_order关联之后的结果再和t_user_guide关联查询吗?还是三张表同时关联之后,再通过where条件过滤?
有一篇播客图,会告诉我们结果。
以上的sql也可以这样进行优化,sao操作来了
SELECT
*
FROM
t_user u
LEFT JOIN t_order o ON o.fuser_account_id = u.fuser_id
LEFT JOIN t_user_guide g ON g.fuser_id = u.fuser_id
AND o.forder_status = 4
AND o.del_flag = 0
WHERE
g.fguide_id = 29
关联查询的时候,会产生临时表,我们可以给临时表加条件,这个操作将会在某些复杂的业务场景遇到。
2.一个标准:
执行DML语句,update和delete操作的时候,需要再sql语句的后面添加limit关键字,防止批量更新,需要对生产环境保持敬畏。
-- 影响行数1行
UPDATE t_user SET fnick_name = '小学生' WHERE fuser_id = 9348 LIMIT 1;
3.注意:
查询一个对象是否存在,我们通过count函数可以查询是否存在,也可以使用limit 1来查询是否存在,
count是全表扫描,limit 1是遇到有1条,停止扫描。
sql优化开始
避免不走索引的场景
①尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描
优化:遵循左匹配原则
②尽量避免使用 in 和 not in,会导致引擎走全表扫描
优化方式:如果是连续数值,可以用 between 代替。
如果是子查询,可以用 exists 代替。
③尽量避免使用 or,会导致数据库引擎放弃索引进行全表扫描
优化方式:可以用 union 代替 or。
④尽量避免进行 null 值的判断,会导致数据库引擎放弃索引进行全表扫描
优化方式:可以给字段添加默认值 0,对 0 值进行判断。
⑤尽量避免在 where 条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描
-- 全表扫描
SELECT * FROM T WHERE score/10 = 9
-- 走索引
SELECT * FROM T WHERE score = 10*9
⑥当数据量大时,避免使用 where 1=1 的条件
优化方式:用代码拼装 SQL 时进行判断,没 where 条件就去掉 where,有 where 条件就加 and。
⑦查询条件不能用 <> 或者 !=
使用索引列作为条件进行查询时,需要避免使用<>或者!=等判断条件。
如确实业务需要,使用到不等于符号,需要在重新评估索引建立,避免在此字段上建立索引,改由查询条件中其他索引字段代替。
⑧where 条件仅包含复合索引非前置列
如下:复合(联合)索引包含 key_part1,key_part2,key_part3 三列,但 SQL 语句没有包含索引前置列”key_part1”,按照 MySQL 联合索引的最左匹配原则,不会走联合索引。
select col1 from table where key_part2=1 and key_part3=2
⑨隐式类型转换造成不使用索引
select col1 from table where col_varchar=123;
⑩order by 条件要与 where 中条件一致,否则 order by 不会利用索引进行排序
-- 不走age索引
SELECT * FROM t order by age;
-- 走age索引
SELECT * FROM t where age > 0 order by age;
select语句的执行顺序
FROM
<表名> # 选取表,将多个表数据通过笛卡尔积变成一个表。
ON
<筛选条件> # 对笛卡尔积的虚表进行筛选
JOIN <join, left join, right join...>
<join表> # 指定join,用于添加数据到on之后的虚表中,例如left join会将左表的剩余数据添加到虚表中
WHERE
<where条件> # 对上述虚表进行筛选
GROUP BY
<分组条件> # 分组
<SUM()等聚合函数> # 用于having子句进行判断,在书写上这类聚合函数是写在having判断里面的
HAVING
<分组筛选> # 对分组后的结果进行聚合筛选
SELECT
<返回数据列表> # 返回的单列必须在group by子句中,聚合函数除外
DISTINCT
# 数据除重
ORDER BY
<排序条件> # 排序
LIMIT
<行数限制>