MST

星途 面试题库

面试题:MySQL GROUP BY和DISTINCT在高并发场景下的优化策略

在高并发读写的电商数据库环境中,有商品表(product)、订单表(order)、订单详情表(order_detail)。商品表存储商品基本信息,订单表记录订单总体情况,订单详情表记录每个订单包含的商品详情。当大量用户同时查询每个类别商品的销量(使用GROUP BY)以及查询所有购买过的商品ID(使用DISTINCT)时,会出现性能问题。请详细分析可能出现的性能瓶颈,并提出完整的优化策略,包括但不限于数据库架构调整、索引优化、缓存使用等方面。
14.7万 热度难度
数据库MySQL

知识考点

AI 面试

面试题答案

一键面试

性能瓶颈分析

  1. 查询语句层面
    • GROUP BY查询:在高并发下,对大量订单详情表数据按商品类别进行分组统计销量,需要全表扫描订单详情表关联商品表获取类别信息,数据量庞大时性能差。例如,如果订单详情表有千万级数据,每次查询都全表扫描会非常耗时。
    • DISTINCT查询:查询所有购买过的商品ID使用DISTINCT,同样可能需要扫描大量订单详情表数据,并且去重操作在大数据量下开销较大。
  2. 数据库架构层面
    • 高并发读写冲突:电商场景下读写操作频繁,读操作(如上述查询)和写操作(如新增订单、更新库存等)可能会竞争数据库资源,导致锁争用,降低性能。例如,写操作可能会锁住相关表,使得读操作等待。
    • 存储压力:随着业务增长,商品表、订单表和订单详情表数据量不断增大,存储系统的I/O压力会增加,影响查询性能。
  3. 索引层面
    • 如果相关列(如订单详情表中的商品ID、商品表中的类别列)没有合适的索引,查询时无法利用索引快速定位数据,只能全表扫描,大大降低查询效率。

优化策略

  1. 数据库架构调整
    • 读写分离:使用主从复制架构,主库负责写操作(如订单创建等),从库负责读操作(如查询商品销量和购买过的商品ID)。这样可以分散读写压力,减少读写冲突。例如,使用MySQL的主从复制功能,配置多个从库分担读压力。
    • 分库分表
      • 水平分表:对于订单表和订单详情表,按时间(如按月或按季度)进行水平分表。比如订单量过大时,将历史订单数据分到不同的表中,查询时只需查询相关时间段的表,减少单次查询的数据量。
      • 垂直分表:对于商品表,如果某些字段(如商品描述等大文本字段)不经常在查询中使用,可以将其拆分到另外的表中,减少主商品表的冗余数据,提高查询效率。
  2. 索引优化
    • 订单详情表:在商品ID列上创建索引,这样在查询购买过的商品ID(DISTINCT查询)时可以快速定位数据。同时,在订单ID列上创建索引,便于关联订单表。例如在MySQL中使用CREATE INDEX idx_product_id ON order_detail(product_id);创建商品ID索引。
    • 商品表:在类别列上创建索引,便于在统计每个类别商品销量(GROUP BY查询)时快速定位商品类别。例如CREATE INDEX idx_category ON product(category);
  3. 缓存使用
    • 查询结果缓存:对于查询每个类别商品的销量和所有购买过的商品ID这两个相对不频繁变动的查询结果,可以使用缓存(如Redis)。每次查询先从缓存中获取数据,如果缓存中没有再查询数据库,查询后将结果存入缓存。例如在Java中可以使用Spring Cache结合Redis实现缓存功能。
    • 热点数据缓存:对于经常查询的热门商品类别或商品ID等热点数据,可以缓存相关数据,减少数据库查询压力。
  4. SQL语句优化
    • GROUP BY查询:尽量减少不必要的字段选择,只选择需要统计的字段和类别字段,避免全表扫描。例如SELECT category, COUNT(*) AS sales_count FROM order_detail JOIN product ON order_detail.product_id = product.product_id GROUP BY category;
    • DISTINCT查询:考虑使用EXISTS子查询等替代DISTINCT,如果逻辑允许,优化查询性能。例如可以通过关联子查询获取购买过的商品ID集合。