诸位开发者,大家好。我是那个每天对着搜索日志琢磨“人找信息”最优路径的产品人。过去二十多年,我们让中文互联网从杂乱无章走向井井有条,靠的正是对“排序”二字的极致追求。今天把压箱底的心得掏出来,聊聊在MySQL里如何像设计搜索引擎一样优雅地排序,让数据听你指挥,而非反过来折磨你。
先把需求拆成“意图”
搜索引擎接到查询时,第一步是理解意图:用户想按时间、热度还是相关度?MySQL同理。写SQL前先问:我要的是最新、最贵,还是最匹配?意图清晰,索引才能精准。
用索引搭好“倒排”
搜索用倒排索引,MySQL用B+Tree。想让ORDER BY跑得飞快,就给排序字段建索引。单列不够就联合索引,把WHERE里出现的列放在最左,ORDER BY的列紧跟其后。就像我们把网页权重、点击率、时效性揉进一个综合分,数据库也需要你把过滤和排序字段排好队。
巧用FIELD实现“人工置顶”
有时老板要在结果里硬塞一条广告,搜索里叫“阿拉丁”。MySQL可以用FIELD(id, 101, 102, …)把指定ID置顶,再按其他字段排。写法:ORDER BY FIELD(id, 101, 103), created_at DESC。既保留人工干预,又不破坏整体逻辑。
复杂排序交给“计算列+索引”
搜索要算千人千面的相关度,MySQL也能算。把复杂表达式写成生成列,再给它加索引。例如:ALTER TABLE goods ADD COLUMN score INT AS (price * 0.3 + sales * 0.7) STORED, ADD INDEX(score)。查询直接ORDER BY score,既简洁又高效。
分页深坑用“游标”来填
深翻页是搜索和数据库共同的噩梦。传统LIMIT 100000,20会让引擎吐血。解决办法是记住上一页最后一条的排序键,用WHERE created_at < '上一页最后时间' LIMIT 20,就像我们用searchAfter做深度翻页,既省内存又省CPU。
别忘了“Explain”这面镜子
任何优化都要用EXPLAIN照一照,看是否用到索引、是否filesort。就像搜索上线前必看A/B数据,数据库上线前也得看执行计划。看到Using filesort就回去调索引,看到Using index才安心发布。
结语
排序不仅是技术,更是一种对信息秩序的信仰。把每一条数据都当作一条搜索结果,把每一次ORDER BY都当作一次查询意图的回应,你就会像我一样,乐此不疲地打磨那几毫秒的差异。愿诸位的数据世界,也能因排序而井井有条。
——一位仍在调试深夜SQL的搜索老兵
教程:MySQL排序(ORDER BY)速通五步法
目标:让查询结果按指定规则排列,并尽可能快。
步骤1:确认排序字段
写SQL前,先列出所有可能用于排序的列,例如created_at、price、score。
步骤2:建索引
单列排序:CREATE INDEX idx_created ON orders(created_at DESC);
联合排序:CREATE INDEX idx_price_created ON products(price ASC, created_at DESC);
步骤3:写ORDER BY
基础:SELECT * FROM products ORDER BY price ASC;
多列:SELECT * FROM products ORDER BY price ASC, created_at DESC;
自定义顺序:SELECT * FROM products ORDER BY FIELD(id, 5, 1, 3), price ASC;
步骤4:避免深翻页
传统:SELECT * FROM products ORDER BY created_at DESC LIMIT 100000,20;
推荐:SELECT * FROM products WHERE created_at < '上一页最后时间' ORDER BY created_at DESC LIMIT 20;
步骤5:验证执行计划
EXPLAIN SELECT … ORDER BY …;
若Extra列出现“Using filesort”,回步骤2调索引,直到看到“Using index”或至少不再filesort。
掌握这五步,任何排序需求都能像搜索引擎一样高效优雅。