在参与实际项目中,当 MySQL 表的数据量达到百万级时,普通的 SQL 查询效率呈直线下降,而且如果 where 中的查询条件较多时,其查询速度无法容忍。想想可知,假如我们查询淘宝的一个订单详情,如果查询时间高达几十秒,这么高的查询延时,任何用户都会抓狂。因此如何提高 SQL 语句查询效率,显得十分重要。
查询速度慢的原因
1、没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷)
2、I/O 吞吐量小,形成了瓶颈效应。
3、没有创建计算列导致查询不优化。
4、内存不足
5、网络速度慢
6、查询出的数据量过大(可采用多次查询,其他的方法降低数据量)
7、锁或者死锁(这是查询慢最常见的问题,是程序设计的缺陷)
8、sp_lock,sp_who,活动的用户查看,原因是读写竞争资源。
9、返回了不必要的行和列
10、查询语句不好,没有优化
30 种 SQL 查询语句的优化方法:
1、应尽量避免在 where 子句中使用 != 或者 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。
2、应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
1
selectidfrom t wherenumisnull;
可以在 num 上设置默认值 0 ,确保表中 num 列没有 null 值,然后这样查询:
1
selectidfrom t wherenum = 0;
3、对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
4、尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
1
selectidfrom t wherenum = 10ornum = 20;
可以这样查询:
1
2
3
selectidfrom t wherenum = 10
union all
selectidfrom t wherenum = 20;
5、下面的查询也将导致全表扫描:(不能前置百分号)
1
selectidfrom t wherenamelike'%abc%';
若要提高效率,可以考虑全文检索。
6、in 和 not in 也要慎用,否则会导致全表扫描,如:
1
selectidfrom t wherenumin(1, 2, 3);
对于连续的数值,能用 between 就不要用 in 了:
1
selectidfrom t wherenumbetween1and3;
1
2
3
4
5
select xx,phone FROM send a JOIN (
select'13891030091' phone unionselect'13992085916' ………… UNIONSELECT
'13619100234' ) b
on a.Phone=b.phone
--替代下面 很多数据隔开的时候
in('13891030091','13992085916','13619100234'…………)
7、如果在 where 子句中使用参数,也会导致全表扫描。因为 SQL 只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择到运行时;它必须在编译时进行选择。然而,如果在编译时简历访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
1
selectidfrom t wherenum = @num;
可以改为强制查询使用索引:
1
selectidfrom t with(index(索引名)) wherenum = @num;
8、应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
1
selectidfrom t wherenum/2 = 100;
应改为:
1
selectidfrom t wherenum = 100 * 2;
9、应尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
1
2
selectidfrom t wheresubstring(name, 1, 3) = ’abc’–name; //以abc开头的id
selectidfrom t wheredatediff(day,createdate,’2005-11-30′) = 0–’2005-11-30′; //生成的id
应改为:
1
2
selectidfrom t wherenamelike ‘abc%’
selectidfrom t where createdate >= ’2005-11-30′ and createdate < ’2005-12-1′;
10、不要在 where 子句中的 “=” 左边进行函数,算术运算或者其他表达式运算,否则系统将可能无法正确使用索引。