面试题答案
一键面试索引列选择
- 地区列:
users
表中的region
列,因为我们需要按地区进行分组,在region
列上创建索引有助于快速定位不同地区的数据。 - 订单日期列:
orders
表中的order_date
列,由于要按月份进行分组,日期列对分组操作有帮助。可以考虑将日期列提取出月份部分,若数据库支持函数索引,可基于DATE_TRUNC('month', order_date)
创建索引(如PostgreSQL支持此函数索引),否则直接对order_date
列创建索引也有助于按月份筛选数据。 - 订单总金额列:
orders
表中的total_amount
列,虽然查询是按地区和月份分组后计算总金额,但在最终排序时要按总金额降序排列,对该列创建索引有助于排序操作。
索引类型考量
- 普通B+树索引:适用于上述列。对于
region
、total_amount
列普通B+树索引即可满足需求。对于order_date
列,如果使用函数索引(如基于DATE_TRUNC('month', order_date)
),在一些支持函数索引的数据库(如PostgreSQL)中,普通B+树函数索引能有效工作。 - 联合索引:可以考虑在
orders
表上创建联合索引,如(user_id, order_date, total_amount)
,其中user_id
是连接orders
表和users
表的关键列,将其放在联合索引开头有助于连接操作,接着是order_date
利于按月份分组,最后是total_amount
利于最终排序。不过要注意联合索引列的顺序很重要,顺序不当可能无法充分利用索引。
优化后的SQL语句(以MySQL为例)
SELECT
u.region,
MONTH(o.order_date) AS month,
SUM(o.total_amount) AS total_amount
FROM
orders o
JOIN
users u ON o.user_id = u.user_id
GROUP BY
u.region, MONTH(o.order_date)
ORDER BY
total_amount DESC;
在上述SQL执行前,在users
表的region
列创建普通索引,在orders
表的user_id
、order_date
、total_amount
列(或按上述联合索引方式)创建索引,以优化查询性能。不同数据库在创建索引语法和函数索引支持上略有差异,需根据实际使用的数据库进行调整。