2016-10-27 4 views
0

У меня есть таблица медицинских диагностических кодов, с помощью которых пользователи могут выполнять поиск по ключевым словам. У меня есть столбец описательного текста, а также столбец синонимов, оба из которых рассматриваются. Результаты представлены в формате автоматического предложить и текущая реализация запроса является слишком медленной для развертывания:Оптимизация полнотекстового запроса MySQL

SELECT 
    ID AS data, CONCAT('[', ICD10, '] ', description) AS value, 
    MAX(MATCH(description) AGAINST("fracture forearm current init oth" IN BOOLEAN MODE) + 
     (MATCH(synonyms) AGAINST("fracture forearm current init oth" IN BOOLEAN MODE) * 0.5)) AS relevance 
FROM Code 
WHERE 
    (MATCH(description) AGAINST("fracture forearm current init oth" IN BOOLEAN MODE) OR 
    MATCH(synonyms) AGAINST ("fracture forearm current init oth" IN BOOLEAN MODE)) AND 
    isPCS = 0 AND 
    isEnabled = 1 AND 
    ICD10 IS NOT NULL AND 
    description IS NOT NULL 
GROUP BY ID 
ORDER BY relevance DESC 
LIMIT 100 

Есть ~ 170K строк в таблице, хотя последние четыре статических ограничений уменьшить его до ~ 94K строка , из которых ~ 16K имеют синонимы. Типичный запрос занимает 0,45 секунды на моем рабочем столе (i7-4770K) и около 0,75 секунды на нашем сервере разработки (нижний конец Xeon). Удаление ключевого слова ORDER BY уменьшает его до 0,02 и 0,05 секунд, соответственно.

Я ожидал, что сортировка результатов будет тривиальной по сравнению с полнотекстовым поиском, но это, похоже, не так. Мне не хватает вопиющей неэффективности?

Я также изучаю, в конце концов, восстановление этой функциональности поверх Lucene/Solr (приветствовались мнения/предложения), но я хотел бы лучше понять это поведение, и оптимизированное временное решение не повредит или.

ответ

2

Если вы order by relevance limit 100, это означает, что MySQL должен найти все строки, соответствующие вашему состоянию, оценить формулу relevance, сделать файл-файл и перенести первые 100 из них.

Если вы не заказываете, это значит, что MySQL должен найти 100 строк, которые соответствуют условиям, и может остановить выполнение там.

Так что это не файл-компьютер после нахождения результата, который делает его медленным, это то, что он должен найти все результаты перед выполнением fileort (и, вероятно, есть намного больше, чем 100 строк, которые имеют по крайней мере некоторые из слова, которые вы ищете).

Но есть на самом деле оптимизация вы можете использовать здесь: использовать полнотекстовый индекс на обоих столбцы вместе:

CREATE FULLTEXT INDEX idxft_Code_descr_syn ON Code (description, synonyms); 

, а затем непосредственно искать в обеих столбцах вместе и упорядочить по полнотекстовой релевантности непосредственно без перерасчета :

SELECT 
    ID AS data, CONCAT('[', ICD10, '] ', description) AS value, 
    MATCH(description, synonyms) 
    AGAINST("fracture forearm current init oth" IN BOOLEAN MODE) AS relevance 
FROM Code 
WHERE 
    MATCH(description, synonyms) 
    AGAINST("fracture forearm current init oth" IN BOOLEAN MODE) AND 
    isPCS = 0 AND 
    isEnabled = 1 AND 
    ICD10 IS NOT NULL AND 
    description IS NOT NULL 
ORDER BY relevance 
LIMIT 100 

Это будет немного изменить свою релевантность по сравнению с текущим заказом, потому что он не будет весить synomym колонки иначе, чем description колонки, но с Реза Ульт был нормализован для своей отдельной колонки, ваши текущие веса, возможно, не имели ожидаемого эффекта.

order by relevance по-прежнему требует полного поиска в таблице, но из-за того, как работают полнотекстовые индексы (они должны заказывать по релевантности), вы, вероятно, получите из него спускную скорость (хотя любой из указанных вами специализированных поисковые системы будут быстрее, чем MySQL общего назначения.Если они необходимы для строк в 170 тыс., вам нужно протестировать. Больше оперативной памяти иногда может стоить тоже. Но это совсем другая тема.)

+0

Я понял, что 'LIMIT' не сохраняет никаких ресурсов при сортировке, но не то, что я мог бы сделать совместный индекс так легко. Это делает его прочным до <0,07 секунды в каждом тестовом случае. Благодаря! –

Смежные вопросы