MySQL中比FIND_IN_SET更快的查询方法(逗号分隔长整型)
优化MySQL存储过程中FIND_IN_SET的查询性能
首先确保network.network_edges表的id字段存在主键索引或普通索引,这是所有优化方案生效的基础。以下是针对Azure MySQL 8.0的几种优化方案:
方案1:使用JSON_TABLE拆分逗号分隔字符串
利用MySQL 8.0原生支持的JSON_TABLE函数,将输入的逗号分隔字符串转换为临时表,通过JOIN关联原表,让查询能命中id字段的索引。
CREATE PROCEDURE `sel_network_edges_by_id`( IN input_ids TEXT ) BEGIN SELECT ne.id, ne.gradient, ne.geoJson, ... FROM network.network_edges ne JOIN JSON_TABLE( CONCAT('[', input_ids, ']'), -- 将逗号字符串转为JSON数组格式 '$[*]' COLUMNS(id BIGINT PATH '$') ) AS ids ON ne.id = ids.id; END
方案2:动态生成IN子句(预处理语句)
将输入的input_ids直接拼接为IN子句,通过预处理语句执行,让MySQL利用索引进行范围查找。注意需确保输入仅包含数字和逗号,避免SQL注入风险。
CREATE PROCEDURE `sel_network_edges_by_id`( IN input_ids TEXT ) BEGIN -- 可选:校验输入格式,仅允许数字和逗号 IF NOT input_ids REGEXP '^[0-9]+(,[0-9]+)*$' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '输入格式无效,仅允许逗号分隔的数字'; END IF; SET @sql = CONCAT( 'SELECT id, gradient, geoJson, ... FROM network.network_edges WHERE id IN (', input_ids, ')' ); PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt; END
方案3:改用JSON数组作为输入参数
调整存储过程的输入参数为JSON数组类型,直接通过JSON_TABLE解析后关联原表,格式更规范且易于校验。
CREATE PROCEDURE `sel_network_edges_by_id`( IN input_ids JSON ) BEGIN -- 可选:校验输入是否为非空JSON数组 IF NOT JSON_VALID(input_ids) OR JSON_TYPE(input_ids) != 'ARRAY' THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '输入必须为有效的JSON数组'; END IF; SELECT ne.id, ne.gradient, ne.geoJson, ... FROM network.network_edges ne JOIN JSON_TABLE( input_ids, '$[*]' COLUMNS(id BIGINT PATH '$') ) AS ids ON ne.id = ids.id; END
方案对比
- 方案1和3:无需担心SQL注入,性能稳定,能充分利用索引,推荐优先使用。
- 方案2:性能最优但需严格校验输入格式,适合信任输入来源的场景。
内容的提问来源于stack exchange,提问作者Liam
相关产品推荐
相关产品推荐

