MST
星途 面试题库

面试题:MySQL 优化数据检索及性能调优相关的复杂查询

现有一个非常大的电商订单表orders,结构为(order_id INT, user_id INT, order_date DATE, total_amount DECIMAL(10,2)),以及用户表users,结构为(user_id INT, user_name VARCHAR(50))。要统计每个月不同用户的订单总金额,并且只显示订单总金额排名前10的用户及其每月订单总金额,同时要保证查询性能最优,写出对应的SELECT语句,并阐述优化思路。
35.9万 热度难度
数据库MySQL

知识考点

AI 面试

面试题答案

一键面试

SELECT语句

WITH MonthlyOrderAmount AS (
    SELECT
        u.user_id,
        u.user_name,
        DATE_FORMAT(o.order_date, '%Y-%m') AS month,
        SUM(o.total_amount) AS total_order_amount
    FROM
        users u
    JOIN
        orders o ON u.user_id = o.user_id
    GROUP BY
        u.user_id, u.user_name, DATE_FORMAT(o.order_date, '%Y-%m')
),
RankedMonthlyOrderAmount AS (
    SELECT
        user_id,
        user_name,
        month,
        total_order_amount,
        ROW_NUMBER() OVER (PARTITION BY month ORDER BY total_order_amount DESC) AS ranking
    FROM
        MonthlyOrderAmount
)
SELECT
    user_id,
    user_name,
    month,
    total_order_amount
FROM
    RankedMonthlyOrderAmount
WHERE
    ranking <= 10;

优化思路

  1. 索引优化
    • orders表的user_idorder_date列上创建联合索引,即CREATE INDEX idx_user_date ON orders(user_id, order_date);。这样在连接users表和orders表时,以及按order_date进行分组时,可以利用索引快速定位数据,提升查询性能。
    • users表的user_id列上确保有索引,如果没有,创建索引CREATE INDEX idx_user_id ON users(user_id);,以加速连接操作。
  2. 使用CTE(Common Table Expressions)
    • 通过CTE将复杂的查询分解为多个逻辑步骤,使查询更易读,同时数据库优化器可以对每个CTE进行独立优化。第一个CTE MonthlyOrderAmount计算每个用户每月的订单总金额,第二个CTE RankedMonthlyOrderAmount对每个月的订单总金额进行排名。
  3. 避免函数操作:虽然在这个查询中DATE_FORMAT函数是必要的,但在其他情况下,应尽量避免在查询条件或连接条件的列上使用函数,因为这会阻止索引的使用。例如,如果要过滤某个月的数据,最好是将日期范围以BETWEEN的形式进行比较,而不是在日期列上使用函数。
  4. 分区表(如果适用):如果数据量非常大,可以考虑对orders表按order_date进行分区,例如按月分区。这样在查询某个月的数据时,可以快速定位到对应的分区,减少扫描的数据量,提升查询性能。