1-11 让SQL飞起来
使用高效的查询
参数是子查询时,使用EXISTS代替IN。
两个代码对比:
--慢
SELECT
*
FROM
Class_A
WHERE
id IN (SELECT
id
FROM
Class_B)
--快
SELECT
*
FROM
Class_A
WHERE
EXISTS( SELECT
*
FROM
Class_B
WHERE
A.id = B.id)
原因:
- 如果连接列(id)上建立了索引,那么查询Class_B时不要查实际的表,只需查索引就可以了。
- 如果使用EXISTS,那么只要查到一行数据满足条件就会终止查询,不用像使用IN时一样扫描全表,这点上NOT EXISTS也一样。
当IN的参数是子查询时,数据库会首先执行子查询,然后将结果存储在一张临时的工作表里(内联视图),然后扫描整个视图。使用EXISTS的话,数据库不会生成临时的工作表。
参数是子查询时,使用连接代替IN。
--使用连接代替IN
SELECT
A.id, A.name
FROM
Class_A A
INNER JOIN
Class_B ON A.id = B.id
这种写法至少用到一张表的"id"列上的索引。而且没有子查询,数据库也不会生成一张中间表。
避免排序
SQL中会进行排序的运算有:
- GROUP BY 子句
- ORDER BY 子句
- 聚合函数(SUM、COUNT、AVG、MAX、MIN)
- DISTINCT
- 集合运算符(UNION、INTERSECT、EXCEPT)
- 窗口函数(RANK、ROW_NUMBER等)
思考:如何从上面的商品表Items中找出同时存在于销售记录表SalesHistory中的商品。换言之,找出有销售记录的商品。
SELECT
I.item_no
FROM
Items I
INNER JOIN
SalesHistory SH ON I.item_no = SH.item_no
因为是一对多的连接,所以"item_no"列中会出现重复数据。为了排除重复数据,需要使用DISTINCT。
更好的做法是使用EXISTS。
SELECT
I.item_no
FROM
Items I
WHERE
EXISTS( SELECT
*
FROM
SalesHistory SH
WHERE
I.item_no = SH.item_no)
在极值函数中使用索引(MAX/MIN)
使用这两个函数时都会进行排序。但是如果参数字段上建有索引,则只需要扫描索引,不需要扫描整个表。
-- 这样写需要扫描全表
SELECT MAX(item) FROM Items
-- 这样写能用到索引
SELECT MAX(item_no) FROM Items
因为item_no是表Items的唯一索引,所以效果更好。
能写在WHERE子句里的条件不要写在HAVING子句里
-- 聚合后使用HAVING子句过滤
SELECT
sale_date, SUM(quantity)
FROM
SalesHistory
GROUP BY sale_date
HAVING sale_date = '2017-10-01'
--聚合前使用WHERE子句过滤
SELECT
sale_date, SUM(quantity)
FROM
SalesHistory
WHERE
sale_date = '2017-10-01'
GROUP BY sale_date
从性能上看,第二条语句写法效率更高。原因:
- 使用 GROUP BY 子句聚合时会进行排序,如果事先通过WHERE 子句筛选出一部分行,就能够减轻排序的负担。
- WHERE子句的条件里可以使用索引。HAVING子句是针对聚合后生成的视图进行筛选的,但是很多时候聚合后的视图都没有继承原表的索引结构。
在GROUP BY 子句和ORDER BY 子句使用索引
一般来讲,GROUP BY 子句和 ORDER BY 子句都会进行排序,来对行进行排列和替换。不过,通过指定带索引的列作为GROUP BY 和 ORDER BY 的列,可以实现快速查询。
真的用到索引了吗
下面几种否定形式不能用到索引
- <>
- !=
- NOT IN
减少中间表
在 SQL 中,子查询的结果会被看成一张新表,这张新表与原始表一样,可以通过代码进行操作。
- 灵活使用HAVING子句
- 需要对多个字段使用IN谓词时,将它们汇总到一处
- 先连接再进行聚合
SELECT sale_date,MAX(quantity)
FROM SalesHistory
GROUP BY sale_date
HAVING MAX(quantity) >=10
SELECT * FROM Addresses1 A1
WHERE (id,state,city)
IN (SELECT id,state,city
FROM Addresses2 A2)