面试题答案
一键面试性能瓶颈分析
- 数据量巨大:
orders
表有数百万条记录,payments
表有大量支付记录,在连接操作时可能导致笛卡尔积过大,消耗大量内存和时间。 - 多表连接:涉及五个表的连接操作,连接条件复杂,容易使查询优化器生成不佳的执行计划。
- 过滤条件:在大表上应用
order_status = '完成'
和已支付等过滤条件,如果相关字段没有合适的索引,全表扫描会严重影响性能。
优化方案
- 索引优化:
- 在
orders
表的order_status
字段上创建索引,加快订单状态过滤。 - 在
orders
表的customer_id
字段上创建索引,加速与customers
表的连接。 - 在
payments
表的order_id
字段上创建索引,加速与orders
表的连接。 - 在
order_items
表的order_id
和product_id
字段上分别创建索引,加速连接操作。
- 在
- 查询改写:
- 减少中间结果集,先在
orders
和payments
表中筛选出符合条件的订单,再与其他表连接。 - 合理使用临时表或CTE(Common Table Expressions),将中间结果缓存,避免重复计算。
- 减少中间结果集,先在
优化后的SQL语句(以MySQL为例)
WITH filtered_orders AS (
SELECT o.order_id
FROM orders o
JOIN payments p ON o.order_id = p.order_id
WHERE o.order_status = '完成'
),
order_item_info AS (
SELECT oi.order_id, oi.product_id, p.product_name
FROM order_items oi
JOIN products p ON oi.product_id = p.product_id
WHERE oi.order_id IN (SELECT order_id FROM filtered_orders)
)
SELECT
c.customer_type,
oii.product_name,
AVG(p.payment_amount) AS average_payment_amount
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
JOIN order_item_info oii ON o.order_id = oii.order_id
JOIN payments p ON o.order_id = p.order_id
WHERE o.order_id IN (SELECT order_id FROM filtered_orders)
GROUP BY c.customer_type, oii.product_name;
上述SQL语句首先使用CTE filtered_orders
筛选出已支付且订单状态为完成的订单ID。然后,order_item_info
CTE获取订单中的商品信息。最后,通过连接customers
、orders
、order_item_info
和payments
表,并结合GROUP BY
计算不同客户类型下每种商品的平均支付金额。