
1) 【一句话结论】:针对千万级用户行为日志,需按时间分表(如按天)、按用户/设备分库,并构建复合索引(user_id, ts, device_type),以控制单表数据量并覆盖查询维度,实现高效查询。
2) 【原理/概念讲解】:用户行为日志属于时间序列数据,数据量每天千万条,需通过分库分表将大表拆分为多个小表,降低单表压力。分库分表分为垂直分库(按业务维度,如按用户ID分库)和水平分片(按时间维度,如按天分表)。索引方面,由于查询条件包含用户ID、时间范围、设备类型,采用B+树结构的复合索引,按(user_id, ts, device_type)排序,利用索引覆盖查询条件,减少回表。时间序列数据按时间有序,分表按天可利用时间有序性加速范围查询(如时间范围查询可快速定位多个表)。
3) 【对比与适用场景】:
分库分表策略对比:
| 策略 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 垂直分库 | 按业务维度(如用户ID)拆分表到不同库 | 每个库数据量小,查询时需连接多个库 | 用户维度查询频繁,如按用户ID查询行为 | 需要分布式事务或最终一致性 |
| 水平分片(按时间) | 按时间维度(如天)拆分表 | 单表数据量可控,时间范围查询高效 | 日志类数据,按时间有序 | 需要表名管理(如带日期后缀) |
索引策略对比:
| 索引类型 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 单字段索引 | 仅索引一个字段 | 查询时需回表 | 单字段查询 | 无法支持复合查询 |
| 复合索引(覆盖索引) | 索引包含查询所有字段 | 查询时无需回表 | 复合查询(如多条件过滤) | 索引大小随字段数增加 |
4) 【示例】:表结构(伪代码):
CREATE TABLE user_behavior_log (
log_id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
ts TIMESTAMP NOT NULL,
device_type VARCHAR(20) NOT NULL,
action VARCHAR(100),
INDEX idx_user_ts_device (user_id, ts, device_type) -- 复合索引
) ENGINE=InnoDB;
-- 分库分表策略
-- 分库:按user_id的hash取模,如库1存储user_id % 2 = 0的用户
-- 分表:按ts按天分表,表名格式为daily_log_YYYYMMDD
查询示例(SQL):
SELECT * FROM user_behavior_log
WHERE user_id = 12345
AND ts BETWEEN '2024-01-01 00:00:00' AND '2024-01-02 23:59:59'
AND device_type = 'mobile';
该查询会先通过复合索引定位到user_id=12345的行,再按时间范围和设备类型过滤,索引覆盖所有查询条件,无需回表。
5) 【面试口播版答案】:面试官您好,针对用户行为日志的存储与查询优化,核心思路是结合时间序列特性,通过分库分表控制数据量,再通过索引覆盖查询维度。首先,分库分表:因为每天千万条数据,按用户维度垂直分库(比如每个用户ID对应一个库,或按hash分库),水平分表按时间(如按天分表,表名带日期,如log_20240101),这样每个表数据量可控,查询时只需访问对应表。然后索引设计:针对查询条件(用户ID、时间范围、设备类型),创建复合索引(user_id, ts, device_type),因为查询时通常先按user_id过滤,再按时间范围,最后按设备类型。这样索引覆盖查询条件,减少回表。比如查询某个用户在2024年1月1日到1月2日,设备为手机的行为,索引可以快速定位到对应表和行,提升性能。总结来说,通过分库分表降低单表压力,复合索引覆盖查询维度,能有效支持千万级日志的高效查询。
6) 【追问清单】:
7) 【常见坑/雷区】: