php网站源程序,多语言网站建设 技术,工业设计公司排行,海门做网站如果你遇到类似下面的 SQL 查询#xff1a;
SELECT *
FROM customer c
WHERE 0 (SELECT COUNT(*)FROM orders oWHERE o.customer_id c.customer_id);意味着有人没有遵循 SQL 最佳实践。该语句的作用是查找没有下过订单的客户#xff0c;其中子查询使用了 COUNT 函数统计客…如果你遇到类似下面的 SQL 查询
SELECT *
FROM customer c
WHERE 0 (SELECT COUNT(*)FROM orders oWHERE o.customer_id c.customer_id);意味着有人没有遵循 SQL 最佳实践。该语句的作用是查找没有下过订单的客户其中子查询使用了 COUNT 函数统计客户的订单数量如果结果等于零代表没有订单。
从逻辑上来讲以上查询没有问题但是它可能存在性能问题。原因在于 COUNT 函数需要统计订单数量如果某个客户有大量订单数据库需要计算出一个总数即使客户的订单数量不多仍然需要进行统计。
以下是 MySQL 中的执行计划
EXPLAIN ANALYZE
SELECT *
FROM customer c
WHERE 0 (SELECT COUNT(*)FROM orders oWHERE o.customer_id c.customer_id);- Filter: (0 (select #2)) (cost111563.21 rows1040858) (actual time8.305..7043.840 rows231117 loops1)- Table scan on c (cost111563.21 rows1040858) (actual time6.968..1104.438 rows1048577 loops1)- Select #2 (subquery in condition; dependent)- Aggregate: count(0) (cost1.30 rows2) (actual time0.005..0.005 rows1 loops1048577)- Index lookup on o using customer_id (customer_idc.customer_id) (cost1.15 rows2) (actual time0.004..0.005 rows2 loops1048577)其中Aggregate表示子查询中执行了聚合操作查询的执行时间大概是 7 秒。
实际上这个 COUNT 函数结果对于我们并不重要我们只需要知道客户是否存在订单。这种情况下最简单的方法就是使用 EXISTS 运算符
SELECT *
FROM customer c
WHERE NOT EXISTS (SELECT 1FROM orders oWHERE o.customer_id c.customer_id);如果客户存在任何订单子查询就会获得结果NOT EXISTS 运算符就会排除对应的客户从而避免统计全部订单数据。新的执行计划如下
EXPLAIN ANALYZE
SELECT *
FROM customer c
WHERE NOT EXISTS (SELECT 1FROM orders oWHERE o.customer_id c.customer_id);- Nested loop antijoin (cost217780392498.61 rows2177801765412) (actual time2273.676..3746.089 rows231117 loops1)- Table scan on c (cost111871.61 rows1040858) (actual time2.191..804.896 rows1048577 loops1)- Single-row index lookup on subquery2 using auto_distinct_key (customer_idc.customer_id) (actual time0.000..0.000 rows1 loops1048577)- Materialize with deduplication (cost423621.04..423621.04 rows2092314) (actual time2797.545..2797.545 rows1021689 loops1)- Filter: (o.customer_id is not null) (cost214389.64 rows2092314) (actual time0.811..1372.007 rows2097157 loops1)- Index scan on o using customer_id (cost214389.64 rows2092314) (actual time0.809..1164.613 rows2097157 loops1)新的查询计划使用了 antijoin 连接和物化Materialize执行时间不到 4 秒。
无论用户订单数量多还是少NOT EXISTS 的性能都不会差于 COUNT 函数而且绝大部分情况下它的性能会更好。