MST

星途 面试题库

面试题:MySQL索引优化排序性能的复杂场景分析

假设有一个电商数据库,其中订单表(orders)有字段order_id(主键)、user_id、order_date、total_amount,用户表(users)有字段user_id(主键)、user_name、city。现在业务需求是查询每个城市中订单总金额(total_amount)排名前三的用户订单信息,并且按order_date倒序排列。请分析如何通过合理使用索引来优化此查询的排序性能,给出具体的索引创建策略以及查询SQL,并说明优化的要点和可能面临的问题。
18.8万 热度难度
数据库MySQL

知识考点

AI 面试

面试题答案

一键面试

索引创建策略

  1. orders 表上创建复合索引 idx_order_date_total_amount,以 order_date 降序和 total_amount 降序排列,这样在查询时可以利用索引的有序性进行排序和筛选。
    CREATE INDEX idx_order_date_total_amount ON orders (order_date DESC, total_amount DESC);
    
  2. users 表上创建索引 idx_city,用于快速定位城市。
    CREATE INDEX idx_city ON users (city);
    
  3. orders 表上创建 user_id 索引,因为需要通过 user_id 关联 users 表。
    CREATE INDEX idx_user_id ON orders (user_id);
    

查询SQL

WITH RankedOrders AS (
    SELECT
        o.order_id,
        o.user_id,
        o.order_date,
        o.total_amount,
        ROW_NUMBER() OVER (PARTITION BY u.city ORDER BY o.total_amount DESC, o.order_date DESC) AS rn
    FROM
        orders o
    JOIN
        users u ON o.user_id = u.user_id
)
SELECT
    ro.order_id,
    ro.user_id,
    ro.order_date,
    ro.total_amount,
    u.user_name,
    u.city
FROM
    RankedOrders ro
JOIN
    users u ON ro.user_id = u.user_id
WHERE
    ro.rn <= 3
ORDER BY
    u.city, ro.rn, ro.order_date DESC;

优化要点

  1. 索引覆盖查询:通过创建复合索引 idx_order_date_total_amount,使得查询可以直接从索引中获取 order_datetotal_amount 字段,减少回表操作,提高查询效率。
  2. 利用索引排序:复合索引 idx_order_date_total_amount 已经按照 order_date 降序和 total_amount 降序排列,这样在 ROW_NUMBER() 函数和最终的 ORDER BY 中可以直接利用索引的有序性,避免额外的排序操作。
  3. 减少数据扫描idx_city 索引用于快速定位城市,减少对 users 表全表扫描;idx_user_id 索引用于快速关联 orders 表和 users 表,减少数据检索范围。

可能面临的问题

  1. 索引维护成本:增加索引会增加插入、更新和删除操作的成本,因为数据库需要同时更新索引结构。如果表的数据更新频繁,过多的索引可能会导致性能下降。
  2. 索引空间占用:索引会占用额外的存储空间,特别是对于大数据量的表,可能会导致磁盘空间不足的问题。
  3. 查询优化器选择:查询优化器可能不总是选择我们期望的索引,尤其是在复杂查询或者数据分布不均匀的情况下。此时可能需要使用 FORCE INDEX 提示来强制查询使用特定的索引,但这不是一个通用的解决方案,需要谨慎使用。