索引创建策略
- 在
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);
- 在
users
表上创建索引 idx_city
,用于快速定位城市。
CREATE INDEX idx_city ON users (city);
- 在
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;
优化要点
- 索引覆盖查询:通过创建复合索引
idx_order_date_total_amount
,使得查询可以直接从索引中获取 order_date
和 total_amount
字段,减少回表操作,提高查询效率。
- 利用索引排序:复合索引
idx_order_date_total_amount
已经按照 order_date
降序和 total_amount
降序排列,这样在 ROW_NUMBER()
函数和最终的 ORDER BY
中可以直接利用索引的有序性,避免额外的排序操作。
- 减少数据扫描:
idx_city
索引用于快速定位城市,减少对 users
表全表扫描;idx_user_id
索引用于快速关联 orders
表和 users
表,减少数据检索范围。
可能面临的问题
- 索引维护成本:增加索引会增加插入、更新和删除操作的成本,因为数据库需要同时更新索引结构。如果表的数据更新频繁,过多的索引可能会导致性能下降。
- 索引空间占用:索引会占用额外的存储空间,特别是对于大数据量的表,可能会导致磁盘空间不足的问题。
- 查询优化器选择:查询优化器可能不总是选择我们期望的索引,尤其是在复杂查询或者数据分布不均匀的情况下。此时可能需要使用
FORCE INDEX
提示来强制查询使用特定的索引,但这不是一个通用的解决方案,需要谨慎使用。