搜索历史表需存user_id、keyword、created_at三核心字段,建议加search_count和is_deleted;建表用InnoDB引擎,主键自增,建user_id+created_at联合索引;插入避免重复需先加user_id+keyword唯一索引再用ON DUPLICATE KEY UPDATE;查询最近10条须带WHERE is_deleted=0并ORDER BY created_at DESC LIMIT 10。

搜索历史该存哪些字段
用户每次输入并提交搜索词,就该记一条记录,核心字段必须有:user_id(区分谁搜的)、keyword(原始搜索词,注意去首尾空格)、created_at(时间戳,用 DATETIME 或 TIMESTAMP)。可选但强烈建议加 search_count(默认 1,后续可合并重复词)、is_deleted(软删除标记,避免真删影响统计)。
别存 result_count 或 response_time 这类衍生数据——它们随业务逻辑变化,不该污染历史表结构。
建表语句怎么写才合理
用 ENGINE=InnoDB,主键用自增 id,但查询主要靠 user_id + created_at,所以要建联合索引。避免用 keyword 做主键或唯一键——用户可能搜相同词多次,且长文本索引效率低。
CREATE TABLE `search_history` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `user_id` BIGINT UNSIGNED NOT NULL, `keyword` VARCHAR(255) NOT NULL, `search_count` INT UNSIGNED DEFAULT 1, `is_deleted` TINYINT UNSIGNED DEFAULT 0, `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), INDEX `idx_user_time` (`user_id`, `created_at` DESC), INDEX `idx_user_keyword` (`user_id`, `keyword`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
注意:VARCHAR(255) 足够覆盖绝大多数搜索词;utf8mb4 支持 emoji 和生僻字;DESC 在索引里对分页查最新记录有帮助。
插入时怎么避免重复记录
不是所有重复都要合并——用户连续搜“苹果”两次,是两条独立行为。但若想支持「合并同类项」(比如展示“苹果(3次)”),得用 INSERT ... ON DUPLICATE KEY UPDATE,前提是 user_id + keyword 有唯一约束:
先加唯一索引:
ALTER TABLE search_history ADD UNIQUE KEY `uk_user_keyword` (`user_id`, `keyword`);
再执行插入:
INSERT INTO search_history (user_id, keyword, search_count, created_at) VALUES (123, 'mysql优化', 1, NOW()) ON DUPLICATE KEY UPDATE search_count = search_count + 1, created_at = NOW();
⚠️ 注意:加唯一索引后,如果业务允许同一用户反复搜相同词但保留多条记录(如分析搜索频次分布),就别用这个方案,改用普通 INSERT + 后续聚合查询。
查最近 10 条怎么写不出错
直接 ORDER BY created_at DESC LIMIT 10 是常见写法,但要注意两点:
- 必须走
idx_user_time索引,否则全表扫描——确认EXPLAIN显示key列为该索引 - 如果用户删过历史,要加
WHERE is_deleted = 0过滤,否则软删除失效
正确示例:
SELECT keyword, search_count, created_at FROM search_history WHERE user_id = 123 AND is_deleted = 0 ORDER BY created_at DESC LIMIT 10;
别在应用层做排序和截断——数据库没加 ORDER BY 时,LIMIT 返回顺序不保证,尤其分库分表后更危险。
实际最难的不是建表或查数据,是决定什么时候清理旧记录。自动定时删?按用户配额限制条数?这些策略得和业务方对齐,数据库只负责高效存取,别替产品做决策。










