mysqlsql-likematch-against

slow mysql query with Like / match against


I need to search for the closest Dialcode bigger than the actual one. For example the closest from 33 will be 331 or 332 (if 331 doesn't exist)... So it has to be 33xxxx, 34 is not valid.

These 2 queries work but are too slow (250ms/row):

SELECT Dialcode
FROM table
WHERE (Dialcode LIKE '$var%' AND Dialcode > '$var' AND Price IS NOT NULL)
ORDER BY Dialcode ASC LIMIT 1

SELECT Dialcode
FROM table
WHERE (MATCH(Dialcode) AGAINST ('$var*' IN BOOLEAN MODE) AND Dialcode > '$var'
      AND Price IS NOT NULL)
ORDER BY Dialcode ASC LIMIT 1

My Dialcode is a PRIMARY KEY BIGINT(15).

Is I do this, it's really fast (>1ms/row) but it's not exactly what I need:

SELECT Dialcode
FROM table
WHERE (Dialcode >= '$var' AND Price IS NOT NULL)
ORDER BY Dialcode ASC LIMIT 1

So I guess my problem is the LIKE / MATCH AGAINST.

Any ideas would be appreciated.

UPDATE solution:

Solution adapted from raina77ow suggestion:

SELECT Dialcode FROM table WHERE (( (Dialcode BETWEEN $var * 1 AND ’9’ )
   OR (Dialcode BETWEEN $var * 10 AND $var.’99’ )   
   OR (Dialcode BETWEEN $var * 100 AND $var.’999’ )
OR (Dialcode BETWEEN $var * 1000 AND $var.’9999’ )
…
) AND Price IS NOT NULL) ORDER BY Dialcode ASC LIMIT 1

Thanks guys!


Solution

  • I see that the main problem here is that index is built upon the numeric values of Dialcode - not the string ones. So both queries do not use index at all.

    You can try to build a numeric function, the problem is that this function will have Dialcode in the left part of evaluation - so the index again won't be used.

    Perhaps this approach might be more useful.

    SELECT Dialcode 
    FROM table 
    WHERE ( (Dialcode BETWEEN %value% * 10 AND (%value%*10 + 9) 
       OR (Dialcode BETWEEN %value% * 100 AND (%value%*100 + 99) 
       OR (Dialcode BETWEEN %value% * 1000 AND (%value%*1000 + 999)
       ...
    ) AND Price IS NOT NULL
    ORDER BY Dialcode LIMIT 1;
    

    It's ugly as hell (I even wrote this wrong the first two times - alfasin should get the credit for correcting me), yes, but it should hit the index. The alternative is using UNION (and not OR), but I suppose both queries will be executed the same way (it's not verified, though).