按分隔符处理字符串是开发中的常见需求,接口路径拆分、日志地址切割、URL请求参数提取和逗号分隔ID拆解都属此类,而MySQL并没有内置split分割函数,SUBSTRING_INDEX解析URL参数时最常用的工具,正是这个由官方提供、按分隔符截取两端内容的字符串分割专用函数。

许多开发者仅掌握用两层嵌套提取参数,却不了解正负计数规则、底层执行开销以及它与SUBSTR、REPLACE究竟有多大性能差距。文章以业务里的接口日志提取verify_idf_id参数这一真实场景为基础,从语法和案例讲到优缺点及优化方案。
SUBSTRING_INDEX(str, delim, count)
str:需要分割的原始字符串/表字段;delim:用于分割的标识(分隔符,如=、&、/、,);count:分割计数,可使用正数或负数,核心规则如下:count > 0:按从左到右的顺序分割,截取前count个分隔符左边的全部内容;count < 0:按照从右向左的顺序分割,截取后abs(count)个分隔符右边的全部内容;count = 0:返回值直接为空字符串,不存在业务使用场景。使用=进行分割,取得第1个=左侧的所有字符
SELECT SUBSTRING_INDEX('verify_idf_id=16','=',1);-- 输出:verify_idf_id使用=进行分割,取得最后1个=右侧的所有字符
SELECT SUBSTRING_INDEX('verify_idf_id=16','=',-1);-- 输出:16URL:/openapi/verify_code_identify/?verify_idf_id=16&name=test
首先按verify_idf_id=分割并截取右侧,再依据&分割并截取左侧,从而准确提取数字:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX('/openapi/verify_code_identify/?verify_idf_id=16&name=test','verify_idf_id=',-1),'&',1);-- 输出:16SELECT SUBSTRING_INDEX('1,2,3,4',',',2); -- 输出 1,2SELECT SUBSTRING_INDEX('1,2,3,4',',',-2); -- 输出 3,4表openapi_apilog,path字段存储接口路径:/openapi/verify_code_identify/?verify_idf_id=16,需要单独取出verify_idf_id对应数值。
SELECTlogin_ip,`path`,price,creat_time,SUBSTRING_INDEX(SUBSTRING_INDEX(`path`,'verify_idf_id=',-1),'&',1) AS verify_idf_idFROM openapi_apilog WHERE `user_id` = '{}' AND `date` = '{}';执行逻辑解析:
SUBSTRING_INDEX(path,'verify_idf_id=',-1):将关键词之后的全部内容截出,得到16(存在多参数时为16&xxx);SUBSTRING_INDEX(..., '&', 1):负责截断&后面的多余参数,最终只留下纯数字。不必固定前缀,只要URL中包含verify_idf_id=即可完成提取,能够适应路径前缀变化和参数位置不固定的情况,通用性最强。
必须进行两次完整的字符串遍历,并匹配两次分隔符;数据量越大、字符串越长,CPU开销就越高,在三者中性能最差。
只需一次扫描,即可在单次全字符串遍历中匹配固定文本,性能超过双层分割。
通过计算前缀长度和指针偏移完成截取,不做全量字符匹配;单次运算轻量,性能最佳。
SUBSTR固定截取 > REPLACE字符串替换 > 双层SUBSTRING_INDEX分割
SUBSTR + LENGTH,以提高查询速度;SUBSTRING_INDEX,以性能为代价获得通用性。字符串需要被双层SUBSTRING_INDEX先后遍历两次,所以在日志表达到百万级后,批量查询会明显变慢。
优化:前缀固定时改用SUBSTR方案。
当URL包含多个参数时,如果只使用单层SUBSTRING_INDEX(path,'verify_idf_id=',-1)便会带出&name=xxx等无关文本,必须在外层再嵌套一层&执行分割截断。
-- 匹配失败,无结果SUBSTRING_INDEX(path,'Verify_ID=',-1)
截取能否成功取决于参数名大小写;分隔符必须与原始字符串保持完全相同的大小写。
WHERE在条件或查询字段外包裹SUBSTRING_INDEX、REPLACE、SUBSTR均会使索引失效,转为全表扫描。
优化办法:为高频查询参数新增独立存储字段,提前拆分参数,避免在运行时切割字符串。
开发过程中不要错误写成count=0,否则得到的截取结果为空。
SUBSTRING_INDEX(..., '&',1)能够适配多参数情况,防止多余字符影响结果。