
1) 【一句话结论】:为支持“查询某商品在多个仓库的库存总和”的复杂查询,应通过设计多对多关联的中间表(如商品-仓库-库存表),并构建针对仓库ID和商品ID的组合索引,结合聚合函数优化查询性能,必要时可考虑物化视图预计算结果以提升高频查询效率。
2) 【原理/概念讲解】:首先,商品与仓库是多对多关系(一个商品存在于多个仓库,一个仓库存储多个商品),因此需建立中间表(如商品仓库库存表,字段:商品ID、仓库ID、库存数量)。查询“某商品在多个仓库的库存总和”本质是按商品ID分组,对库存数量求和。数据库优化核心是:① 表结构设计:明确多对多关系,避免冗余;② 索引优化:在商品仓库库存表的仓库ID和商品ID上建组合索引(如仓库ID + 商品ID),因为查询时需要按商品ID分组,而仓库ID用于过滤或分组;③ 聚合优化:使用SUM(库存数量)聚合函数,数据库优化器会尝试使用索引覆盖查询(如果索引包含所有字段)。类比:就像班级(仓库)和学生(商品)的关系,一个学生(商品)属于多个班级(仓库),需要记录每个学生每个班级的学分(库存),查询某个学生的总学分(库存总和),需要按学生分组求和,索引按班级和学生排序,快速定位数据。
3) 【对比与适用场景】:
| 优化方法 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 组合索引(直接查询) | 在中间表仓库ID和商品ID上建组合索引 | 查询时直接通过索引定位数据,无需全表扫描 | 高频查询商品库存总和,且数据量适中(如百万级) | 需确保查询条件匹配索引列,避免索引失效 |
| 物化视图(预计算) | 创建物化视图存储每个商品的总库存(如商品总库存视图,字段:商品ID、总库存) | 预先计算并存储聚合结果,查询时直接读取视图 | 高频查询且允许一定延迟(如每小时/天刷新),减少实时计算压力 | 需定期刷新(如触发器或任务),否则数据可能过时 |
| 分区表(按仓库或商品分区) | 将中间表按仓库ID或商品ID分区(如范围分区、列表分区) | 查询时仅扫描相关分区,减少I/O | 仓库或商品数量极大(如千万级),查询时仅处理部分分区 | 分区键选择需合理,避免跨分区查询 |
4) 【示例】:
CREATE TABLE 商品表 (
商品ID INT PRIMARY KEY,
商品名称 VARCHAR(50)
);
CREATE TABLE 仓库表 (
仓库ID INT PRIMARY KEY,
仓库名称 VARCHAR(50)
);
CREATE TABLE 商品仓库库存 (
商品ID INT,
仓库ID INT,
库存数量 INT,
PRIMARY KEY (商品ID, 仓库ID),
FOREIGN KEY (商品ID) REFERENCES 商品表(商品ID),
FOREIGN KEY (仓库ID) REFERENCES 仓库表(仓库ID)
);
CREATE INDEX idx_仓库ID_商品ID ON 商品仓库库存(仓库ID, 商品ID);
SELECT 商品ID, 商品名称, SUM(库存数量) AS 总库存
FROM 商品仓库库存
JOIN 商品表 ON 商品仓库库存.商品ID = 商品表.商品ID
GROUP BY 商品ID, 商品名称;
CREATE MATERIALIZED VIEW 商品总库存视图 AS
SELECT 商品ID, 商品名称, SUM(库存数量) AS 总库存
FROM 商品仓库库存
JOIN 商品表 ON 商品仓库库存.商品ID = 商品表.商品ID
GROUP BY 商品ID, 商品名称;
-- 定期刷新(如每天凌晨)
REFRESH MATERIALIZED VIEW 商品总库存视图;
5) 【面试口播版答案】:
“面试官您好,针对夏商集团库存查询系统需要支持‘查询某商品在多个仓库的库存总和’的复杂查询,我的核心思路是通过设计多对多关联的中间表,并优化索引和聚合查询。首先,商品与仓库是多对多关系,所以需要建立中间表(比如商品仓库库存表,包含商品ID、仓库ID和库存数量),这样能明确记录每个商品在每个仓库的库存。然后,在中间表上为仓库ID和商品ID建组合索引,因为查询时需要按商品ID分组求和,这个索引能快速定位数据,避免全表扫描。查询语句就是按商品ID分组,用SUM聚合库存数量。如果高频查询,还可以考虑创建物化视图预计算结果,减少实时计算压力,但需要定期刷新保证数据实时性。这样既能提升查询性能,又能满足业务需求。”
6) 【追问清单】:
商品ID + 仓库ID,查询时按仓库ID分组求和,或者对仓库表和中间表进行JOIN后聚合。7) 【常见坑/雷区】:
商品ID,但查询时按仓库ID分组,索引无法有效利用,导致全表扫描。