# 06 索引策略与典型查询模式 本节从“页面/接口会怎么查”出发解释索引的设计意图,并给出可复用的查询模式。 --- ## 1. 索引总体思路 从 `complete_mall_database.sql` / `mall_migration.sql` 中可以看到索引集中在: - 列表页高频过滤字段:`status`、`created_at`、`merchant_id`、`user_id`、`category_id` - 对外访问字段:`cid`、`slug` - 排序/榜单字段:`sale_count`、`rating_avg`、`rating_count`、`base_price` - 多值字段:`tags`(GIN) 其核心理念是: - **读路径优先**:电商最常见的是“列表页 + 详情页”,索引优先覆盖这些路径。 - **SEO 友好**:对外 URL 常用 `cid/slug`,因此为其建索引。 - **避免重计算**:用触发器维护汇总字段(库存/销量),让查询尽量落在单表或轻量 join。 --- ## 2. 典型查询模式与对应索引 > 注:以下 SQL 示例以可读性为主,实际项目可能通过视图(如 `ml_products_detail_view`)或 API 层封装。 ### 2.1 商品列表页(按分类 + 上架状态 + 时间倒序) 典型查询: ```sql select id, cid, name, base_price, main_image_url, sale_count, rating_avg from public.ml_products where category_id = '...category_uuid...'::uuid and status = 1 order by created_at desc limit 20 offset 0; ``` 依赖索引: - `idx_ml_products_category(category_id, status)` - `idx_ml_products_status(status, created_at desc)` ### 2.2 商品列表页(商家后台:按商家 + 状态) ```sql select id, cid, name, status, total_stock, sale_count from public.ml_products where merchant_id = '...merchant_uuid...'::uuid order by updated_at desc limit 50; ``` 依赖索引: - `idx_ml_products_merchant(merchant_id, status)`(也会被 merchant_id 过滤利用) ### 2.3 商品详情页(按 cid 或 slug) ```sql -- 方式 1:cid select * from public.get_product_by_cid(12345); -- 方式 2:slug select * from public.ml_products where slug = 'iphone-15-pro' and status = 1; ``` 依赖索引: - `idx_ml_products_cid(cid)` - `idx_ml_products_slug(slug)` ### 2.4 商品搜索/筛选(按 tags) ```sql select id, cid, name from public.ml_products where status = 1 and tags @> array['手机','苹果']::text[] order by sale_count desc limit 20; ``` 依赖索引: - `idx_ml_products_tags using gin(tags)` 说明: - `tags @> array[...]` 是典型的 GIN 可加速模式。 ### 2.5 订单列表(用户维度) ```sql select id, order_no, total_amount, order_status, created_at from public.ml_orders where user_id = '...user_uuid...'::uuid order by created_at desc limit 20; ``` 依赖索引: - `idx_ml_orders_user(user_id, created_at desc)` ### 2.6 订单列表(商家维度) ```sql select id, order_no, total_amount, order_status, created_at from public.ml_orders where merchant_id = '...merchant_uuid...'::uuid order by created_at desc limit 20; ``` 依赖索引: - `idx_ml_orders_merchant(merchant_id, created_at desc)` ### 2.7 订单按状态过滤(运营/商家后台常见) ```sql select id, order_no from public.ml_orders where order_status in (1,2,3) order by created_at desc limit 50; ``` 依赖索引: - `idx_ml_orders_status(order_status, created_at desc)` ### 2.8 购物车加载 ```sql select c.*, s.price, p.name from public.ml_shopping_cart c left join public.ml_product_skus s on s.id = c.sku_id left join public.ml_products p on p.id = c.product_id where c.user_id = '...user_uuid...'::uuid order by c.updated_at desc; ``` 依赖索引: - `idx_ml_shopping_cart_user(user_id)` --- ## 3. JSONB 字段的索引缺口(建议项) 当前脚本对 `tags` 做了 GIN,但对以下 JSONB 的查询与索引没有“强约束”体现: - `ml_orders.shipping_address` - `ml_shops.address/business_hours` - `ml_coupon_templates.applicable_products/categories` 如果业务上出现以下高频查询: - “按城市/区域筛选订单/店铺” - “某个商品可用哪些券” 建议考虑: - 关系化建模(反向关联表) - 或表达式索引(例如对 JSONB 内部字段建索引) --- ## 4. 索引维护建议 - 新增字段/查询前先用 `EXPLAIN (ANALYZE, BUFFERS)` 验证是否命中索引。 - 避免为低选择性字段(如 `status` 单列)盲目建索引,优先组合索引匹配真实查询。 - 注意 RLS 会影响执行计划与开销,常用过滤字段建议都具备索引(`user_id/merchant_id/status/created_at`)。