2017-10-09 8 views
0

J'ai la requête suivante:MySQL multiples ou est dans OÙ

SELECT 
    b.business_name, 
    b.address, 
    b.city, 
    b.state, 
    b.phone_number, 
    i.date 
FROM business_table b 
LEFT JOIN inspection_table i ON b.id = i.business_id 
WHERE i.date = (
    SELECT MAX(i.date) 
    FROM inspection_table i 
    WHERE b.id = i.business_id 
) 
AND b.city LIKE '%Boston%' 
OR b.city LIKE '%Dallas%' 
OR b.city LIKE '%Seattle%' 
OR b.city LIKE '%New York%' 
OR b.city LIKE '%Portland%' 
OR b.city LIKE '%San Antonio%' 
OR b.city LIKE '%Los Angeles%' 
OR b.city LIKE '%Miami%' 
ORDER BY i.date DESC; 

je reçois le résultat que je suis après, mais la requête est très lent (~ 17s). Y a-t-il une meilleure façon de construire cette requête? Le champ ville est indexé dans la table business_table.

+0

Vous ** ** pourrait utiliser un 'REGEXP' (' b.city REGEXP « Boston | Dallas | Seattle''), mais ce serait en fait probablement être légèrement plus lent. Cela ne devrait pas prendre 17 secondes cependant; Combien de lignes y a-t-il dans votre table? –

+0

~ 32 000 lignes dans ma table – MoreScratch

+0

Avez-vous essayé de mettre des parenthèses autour de votre liste OU? ou voulez-vous "le plus récent de Boston ... et tout de toutes les autres villes"? – Uueerdo

Répondre

1

Un index conventionnel n'aide pas LIKE '%pattern' requêtes du tout. L'index n'est pas utilisé et votre requête doit effectuer une analyse complète de la table.

Vous devez utiliser Full-Text Search Functions si vous voulez effectuer une recherche efficace avec MySQL.

Vous pourriez aimer ma présentation Full Text Search Throwdown, dans laquelle je compare différentes méthodes de recherche de texte pour MySQL.

0

J'ai l'impression que votre OR est erroné, donc c'est ce que je pense que sera la meilleure requête.

SELECT 
    b.business_name, 
    b.address, 
    b.city, 
    b.state, 
    b.phone_number, 
    li.lastInspection AS `date` 
FROM (SELECT business_id, MAX(i.date) as lastInspection 
     FROM inspection_table 
     GROUP BY business_id) AS li 
INNER JOIN business_table b 
ON li.business_id = b.business_id 
WHERE b.city LIKE '%Boston%' 
    OR b.city LIKE '%Dallas%' 
    OR b.city LIKE '%Seattle%' 
    OR b.city LIKE '%New York%' 
    OR b.city LIKE '%Portland%' 
    OR b.city LIKE '%San Antonio%' 
    OR b.city LIKE '%Los Angeles%' 
    OR b.city LIKE '%Miami%' 
ORDER BY li.lastInspection DESC 
; 

Si vous avez un grand nombre des villes ou des entreprises, ce pourrait être lent; mais je parierais un index sur inspection_table (business_id, date) l'accélérerait un peu.

Idéalement, vous obtiendrez vos dernières inspections, trouver leur entreprise et ensuite filtrer les entreprises; Si ce n'est pas le cas, vous pouvez le forcer en mettant tout sauf les conditions WHERE dans une sous-requête, et avoir une requête externe faire le filtrage final.

0

Il semble y avoir plusieurs problèmes dans la formulation de la requête. Les autres réponses ont mis en évidence certaines des corrections. Je vais essayer de résoudre tous les problèmes.

Les parenthèses sont un must - x AND y OR z OR w est traité comme (x AND y) OR z OR w. Cela peut corriger l'intention et la performance. Vous recherchez South Boston et Boston? Aussi Boston Heights? Sinon, supprimez les caractères génériques (%). Cela permettra d'indexer city.

Si vous faites besoin des cartes sauvages, puis en utilisant un indice FULLTEXT et MATCH...AGAINST... va courir beaucoup plus vite.

Avec le leader %, je pense, le REGEXP suggéré Age Obsidian sera plus rapide, car il ferait un seul balayage de city.

Si business_id n'est pas le PRIMARY KEY, ajoutez-les:

INDEX(business_id, date) 
INDEX(business_id, city)