SQL 子查询实现
SELECT
sub.user_id,
sub.product_id,
p.product_name,
sub.max_purchase_amount
FROM
(
SELECT
oi.user_id,
oi.product_id,
MAX(oi.price) AS max_purchase_amount
FROM
(
SELECT
oi.order_item_id,
oi.order_id,
oi.product_id,
oi.price,
o.user_id,
o.order_time
FROM
order_items oi
JOIN
orders o ON oi.order_id = o.order_id
WHERE
o.order_time >= NOW() - INTERVAL 1 HOUR
) AS oi
GROUP BY
oi.user_id, oi.product_id
) AS sub
JOIN
products p ON sub.product_id = p.product_id;
高并发场景下优化策略
- 索引优化:
- 在
orders
表的 order_time
列上创建索引,加速 WHERE o.order_time >= NOW() - INTERVAL 1 HOUR
条件的查询。
- 在
orders
表的 user_id
列上创建索引,加快 JOIN
操作。
- 在
order_items
表的 order_id
列上创建索引,优化 JOIN
操作。
- 在
products
表的 product_id
列上创建索引,加快 JOIN
操作。
- 分区表:
- 对于
orders
表,可以按 order_time
进行时间分区,比如按天分区。这样在查询最近一小时订单时,只需扫描相关的分区,减少数据扫描量。
- 对于
order_items
表,可以根据 order_id
进行分区,因为通常一个订单的商品项会一起处理,分区可以提高查询性能。
- 查询语句优化:
- 尽量减少子查询的嵌套层数,这里虽然使用了子查询,但通过合理设计,将复杂的逻辑逐步拆解,避免了过多的嵌套。
- 使用合适的
JOIN
类型,这里使用 INNER JOIN
确保只返回匹配的数据,减少不必要的数据返回。
锁机制影响及处理
- 行级锁:
- 在高并发环境下,数据库默认使用行级锁。在读取
orders
、order_items
和 products
表数据时,行级锁会锁定正在读取或修改的行。为了减少锁争用,查询尽量按索引顺序访问数据,这样锁的范围会更小,持续时间更短。
- 例如,如果查询是基于
order_time
索引进行筛选,锁会按索引顺序锁定相关行,避免无序锁定导致的锁争用。
- 表级锁:
- 某些操作,如批量插入或删除数据时,可能会使用表级锁。在高并发场景下,表级锁会阻塞其他读写操作,所以要尽量避免长时间持有表级锁。可以将大的操作拆分成小的事务,减少锁的持有时间。
- 例如,将批量插入订单操作拆分成每次插入少量订单的事务,这样每个事务持有表级锁的时间更短,减少对其他操作的影响。
缓存机制影响及处理
- 查询结果缓存:
- 可以缓存查询结果,因为在一定时间内,每个用户最近一小时内购买金额最高的商品信息可能不会频繁变化。使用缓存可以避免重复执行复杂的查询,直接返回缓存的结果。
- 例如,使用 Redis 作为缓存,将查询结果以
user_id
作为键存储在 Redis 中。每次查询时,先检查 Redis 中是否有对应的数据,如果有则直接返回,没有再执行数据库查询并将结果存入 Redis。
- 数据缓存:
- 对于
products
表中的商品信息,可以缓存商品名称等基本信息。这样在查询时,即使 products
表数据发生变化,只要缓存未过期,仍然可以快速返回结果。
- 同时,要注意缓存的更新策略,当商品信息发生变化时,及时更新缓存,避免返回过期数据。可以使用消息队列等机制,在商品数据更新时,异步通知缓存更新。