结论:对超长 URL 字段,前缀索引是最常用且有效的分片索引方案,但必须配合 WHERE 条件中明确使用前缀匹配(如 LIKE 'https://example.com%'),否则无法命中;单纯建 INDEX url(255) 不等于能加速任意子串搜索。

直接说结论:对超长 URL 字段,前缀索引 是最常用且有效的分片索引方案,但必须配合 WHERE 条件中明确使用前缀匹配(如 LIKE 'https://example.com%'),否则无法命中;单纯建 INDEX url(255) 不等于能加速任意子串搜索。
为什么不能对完整 URL 建普通索引?
MySQL 单列索引有长度限制(InnoDB 默认最大 767 字节,utf8mb4 下约 191 个字符),而真实 URL 经常超过 2000 字节。尝试执行:CREATE INDEX idx_url ON logs(url) 会报错:Specified key was too long。即使表启用了 innodb_large_prefix,也受限于页大小和性能损耗——索引越大,B+树层级越深,写入更新成本越高,缓存效率越差。
前缀索引怎么建才真正生效?
前缀索引不是“随便截一段”,它只对**左前缀匹配**有效:
- ✅ 有效场景:
WHERE url LIKE 'https://github.com%'、WHERE url = 'https://github.com/mysql'(等值查询也依赖前缀唯一性) - ❌ 无效场景:
WHERE url LIKE '%github.com'(后缀匹配)、WHERE url LIKE '%/pull/%'(中间匹配)——这些仍会触发全表扫描 - 选多长?用
SELECT COUNT(DISTINCT LEFT(url, 255)) / COUNT(*) FROM logs;算区分度,> 0.95 就够用;低于 0.8 建议加到 300 或换其他字段做索引 - 别忽略
COLLATION:URL 含大小写,确保建索引时用utf8mb4_bin排序规则,避免http://A.com和http://a.com被误判为相同
当需要模糊搜域名或路径怎么办?
前缀索引解决不了 CONTAINS 类需求。这时要拆解问题:
- 提取域名单独建列 + 索引:
ALTER TABLE logs ADD COLUMN domain VARCHAR(255) GENERATED ALWAYS AS (SUBSTRING_INDEX(SUBSTRING_INDEX(url, '://', -1), '/', 1)) STORED;,再CREATE INDEX idx_domain ON logs(domain) - 路径部分用
FULLTEXT(仅限 MyISAM 或 InnoDB 5.6+):ALTER TABLE logs ADD FULLTEXT(url),查时用MATCH(url) AGAINST('login.php' IN NATURAL LANGUAGE MODE) - 绝对避免:
WHERE url REGEXP 'github\.com.*pull'—— 正则在大表上等于全表扫描,哪怕有索引也无用
容易被忽略的坑:前缀索引不支持 ORDER BY 和 GROUP BY
比如 SELECT DISTINCT LEFT(url, 255) FROM logs ORDER BY url,MySQL 无法利用 idx_url(255) 做排序,仍会生成临时表 + filesort。如果业务真要按 URL 排序,要么用完整字段(接受存储代价),要么改用更短的业务标识字段(如 host_path_hash)替代。


















