可以使用索引的Find_in_set的替代方案

时间:2015-05-29 09:13:42

标签: mysql query-optimization

我有一个我的sql存储过程,我将一个数字列表作为逗号分隔的mediumtext字段传递

检查我的参数是否匹配我在我的存储过程中使用Find_in_set,如下所示

SELECT SQL_CALC_FOUND_ROWS f1,f2,f3,f4 FROM `mytable`
WHERE FIND_IN_SET(f2,'1,2,4,5,6,6,7,8,8,4,9,7.......................') > 0
ORDER BY f1 DESC        
LIMIT 25 OFFSET 0
;

SELECT FOUND_ROWS();

现在我发现Find_in_set的问题是它没有使用索引,因为我的查询花了太长时间才完成。 请在查询中建议任何改进

P.S。

以下是我的完整存储过程(包括以下答案中建议的更改)

    DECLARE _calculated_offset INT;
    SET _calculated_offset = _limit * (_pageNumber -1);
    IF _calculated_offset < 0 THEN  
        SET _calculated_offset = 0;
    END IF;         

    /*SELECT SQL_CALC_FOUND_ROWS f1,f2,f3,f4  FROM `mytable`
    WHERE FIND_IN_SET(f1,_telcoIdList) > 0  
    AND FIND_IN_SET(f2,_msisdnList) > 0 
    ORDER BY f3 DESC        
    LIMIT _limit OFFSET _calculated_offset
    ;

    SELECT FOUND_ROWS();*/


SET @query = CONCAT('SELECT SQL_CALC_FOUND_ROWS f1,f2,f3,f4
    FROM `mytable`
    WHERE f1 in (',_telcoIdList,')
    AND f2 in (',_msisdnList,') 
    ORDER BY f3 DESC        
    LIMIT ', _limit,' OFFSET ',_calculated_offset,' ;

    SELECT FOUND_ROWS();

    '); 
    PREPARE stmt FROM @query; 
    EXECUTE stmt; 
    DEALLOCATE PREPARE stmt; 

1 个答案:

答案 0 :(得分:1)

使用预准备语句并更改为in子句

SET @query = CONCAT('SELECT SQL_CALC_FOUND_ROWS f1,f2,f3,f4 FROM mytable
WHERE f2 in (', myinputstr, ') ORDER BY f1 DESC LIMIT 25 OFFSET 0'); 

    PREPARE stmt FROM @query; 

    EXECUTE stmt; 

    DEALLOCATE PREPARE stmt; 

这将允许使用f2索引。

编辑:要包含findrows语句,请使用以下样式

SET @query = CONCAT('SELECT SQL_CALC_FOUND_ROWS f1,f2,f3,f4
    FROM `mytable`
    WHERE f1 in (',_telcoIdList,')
    AND f2 in (',_msisdnList,') 
    ORDER BY f3 DESC        
    LIMIT ', _limit,' OFFSET ',_calculated_offset); 
    PREPARE stmt FROM @query; 
    EXECUTE stmt; 
    DEALLOCATE PREPARE stmt; 

    SELECT FOUND_ROWS();

BTW,在查询中也添加了SQL_CALC_FOUND_ROWS