2015-10-21 1 views
6

Je travaille sur un site Web en cours d'exécution sur Propel ORM et j'ai cette requête:MySQL match ... Contre requête très lent

if(isset($args["QueryText"]) && $args["QueryText"] != "") { 
    $query = $query 
    ->withColumn("(MATCH (Request.Subject, Request.Detail) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE) + MATCH (Response.Response) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE))", "RequestRelevance") 
    ->condition('cond1', "(MATCH (Request.Subject, Request.Detail) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE) + MATCH (Response.Response) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE)) > 0.2") 
    ->condition('cond2', 'Request.Id = ?', $args["QueryText"]) 
    ->where(array('cond1', 'cond2'), 'or') 
    ->orderBy("RequestRelevance", Criteria::DESC); 
} 

qui se traduit par ce qui suit dans SQL:

SELECT DISTINCT 
(MATCH (requests.subject, requests.detail) AGAINST ('46104' IN BOOLEAN MODE) + 
    MATCH (Response.response) AGAINST ('46104' IN BOOLEAN MODE)) 
    AS RequestRelevance, requests.requestID AS "Id", requests.subject AS "Subject", requests.detail AS "Detail", requests.created AS "CreatedDate", requests.lastresponsedate AS "LastResponseDate", SupportStatus.supportstatusID AS "SupportStatus.Id", SupportStatus.supportstatus AS "SupportStatus.Name", SupportStatus.isnew AS "SupportStatus.IsNew", SupportStatus.isclosed AS "SupportStatus.IsClosed", CustomerGroup.customergroupID AS "CustomerGroup.Id", CustomerGroup.customergroup AS "CustomerGroup.Name", Site.siteID AS "Site.Id", Site.site AS "Site.Name", InternalUser.userID AS "InternalUser.Id", InternalUser.username AS "InternalUser.Username", User.userID AS "User.Id", User.username AS "User.Username", Customer.customerID AS "Customer.Id", Customer.customer AS "Customer.Name", Customer.customergroupID AS "Customer.CustomerGroupId", Customer.rate AS "Customer.Rate" 
FROM requests 
    LEFT JOIN responses Response ON (requests.requestID=Response.requestID) 
    INNER JOIN supportstatus SupportStatus ON (requests.supportstatusID=SupportStatus.supportstatusID) 
    INNER JOIN customergroups CustomerGroup ON (requests.customergroupID=CustomerGroup.customergroupID) 
    INNER JOIN customers Customer ON (requests.customerID=Customer.customerID) 
    INNER JOIN sites Site ON (requests.siteID=Site.siteID) 
    LEFT JOIN users InternalUser ON (requests.twistedfish_userID=InternalUser.userID) 
    LEFT JOIN users User ON (requests.userID=User.userID) 
WHERE ((MATCH (requests.subject, requests.detail) AGAINST ('46104' IN BOOLEAN MODE) + 
    MATCH (Response.response) AGAINST ('46104' IN BOOLEAN MODE)) > 0.2 OR requests.requestID = '46104') 
ORDER BY requests.created ASC,RequestRelevance DESC 

Il prend une bonne 20 secondes pour charger sur le site Web en utilisant Propel et 7.020 secondes lors de l'exécution de la requête SQL.

J'ai essayé la suivante à la place:

SELECT DISTINCT 
    requests.requestID AS "Id", requests.subject AS "Subject", requests.detail AS "Detail", requests.created AS "CreatedDate", requests.lastresponsedate AS "LastResponseDate", SupportStatus.supportstatusID AS "SupportStatus.Id", SupportStatus.supportstatus AS "SupportStatus.Name", SupportStatus.isnew AS "SupportStatus.IsNew", SupportStatus.isclosed AS "SupportStatus.IsClosed", CustomerGroup.customergroupID AS "CustomerGroup.Id", CustomerGroup.customergroup AS "CustomerGroup.Name", Site.siteID AS "Site.Id", Site.site AS "Site.Name", InternalUser.userID AS "InternalUser.Id", InternalUser.username AS "InternalUser.Username", User.userID AS "User.Id", User.username AS "User.Username", Customer.customerID AS "Customer.Id", Customer.customer AS "Customer.Name", Customer.customergroupID AS "Customer.CustomerGroupId", Customer.rate AS "Customer.Rate" 
FROM requests 
    LEFT JOIN responses Response ON (requests.requestID=Response.requestID) 
    INNER JOIN supportstatus SupportStatus ON (requests.supportstatusID=SupportStatus.supportstatusID) 
    INNER JOIN customergroups CustomerGroup ON (requests.customergroupID=CustomerGroup.customergroupID) 
    INNER JOIN customers Customer ON (requests.customerID=Customer.customerID) 
    INNER JOIN sites Site ON (requests.siteID=Site.siteID) 
    LEFT JOIN users InternalUser ON (requests.twistedfish_userID=InternalUser.userID) 
    LEFT JOIN users User ON (requests.userID=User.userID) 
WHERE (requests.subject LIKE '%46104%' OR requests.detail LIKE '%46104%' OR Response.response LIKE '%46104%' OR requests.requestID = '46104') 
ORDER BY requests.created 

qui prend 3.308 secondes pour exécuter. La suppression de OR Response.response LIKE '%46104%' réduit le temps à 0.140 secondes. La table de réponses contient 288317 lignes et la colonne responses.responses est une colonne TEXT() avec un index FULLTEXT.

Quel serait le meilleur moyen de réduire le temps d'exécution de cette recherche? Je l'ai essayé d'utiliser cette réponse https://dba.stackexchange.com/questions/15214/why-is-like-more-than-4x-faster-than-match-against-on-a-fulltext-index-in-mysq mais quand j'Execute:

SELECT responseID FROM 
(
SELECT * FROM responses 
WHERE requestID = 15000 
AND responseID != 84056 
) A 
WHERE MATCH(response) AGAINST('twisted'); 

Je reçois cette erreur:

Error Code: 1191. Can't find FULLTEXT index matching the column list

aide sera grandement appréciée!

EDIT 1:

Essayé la requête de @Richard EB:

ALTER TABLE responses ADD FULLTEXT(response) 
288317 row(s) affected Records: 288317 Duplicates: 0 Warnings: 0 78.967 sec 

Cependant:

SELECT responseID FROM ( SELECT * FROM responses  WHERE requestID = 15000  AND responseID != 84056) A WHERE MATCH(response) AGAINST('twisted') LIMIT 0, 2000 
Error Code: 1191. Can't find FULLTEXT index matching the column list 0.000 sec 

Retrait DISTINCT réduit le temps d'exécution à 0,952 secondes mais il ne récupère pas les résultats dont j'ai besoin.

EDIT 2:

L'exécution de cette requête:

SELECT DISTINCT 
responses.requestID AS "Id" FROM responses WHERE MATCH(response) AGAINST('twisted') 

prend 0.062 secondes.

exécution ceci:

SELECT DISTINCT responses.requestID 
    FROM responses 
WHERE (
    MATCH (Responses.response) AGAINST ('twisted' IN BOOLEAN MODE) 
) 
ORDER BY responses.requestID ASC 

ne prend 0.046 secondes. Toutefois, la sélection à partir de Demandes et l'adhésion à des réponses est ce qui ralentit la requête. Je ne suis pas sûr si cela signifie que toute la requête doit être complètement réécrite pour sélectionner des réponses et joindre des demandes à la place?

EDIT 3:

Voici les indices que j'ai sur Requests et Responses tables:

# Table, Non_unique, Key_name, Seq_in_index, Column_name, Collation, Cardinality, Sub_part, Packed, Null, Index_type, Comment, Index_comment 
    responses, 0, PRIMARY, 1, responseID, A, 288317, , , , BTREE, , 
    responses, 1, requestID, 1, requestID, A, 48052, , , YES, BTREE, , 
    responses, 1, response, 1, response, , 1, , , YES, FULLTEXT, , 
    responses, 1, response_2, 1, response, , 1, , , YES, FULLTEXT, , 
    responses, 1, response_3, 1, response, , 1, , , YES, FULLTEXT, , 

    # Table, Non_unique, Key_name, Seq_in_index, Column_name, Collation, Cardinality, Sub_part, Packed, Null, Index_type, Comment, Index_comment 
    requests, 0, PRIMARY, 1, requestID, A, 46205, , , , BTREE, , 
    requests, 1, supportstatusID, 1, supportstatusID, A, 14, , , YES, BTREE, , 
    requests, 1, twistedfish_userID, 1, twistedfish_userID, A, 344, , , YES, BTREE, , 
    requests, 1, customergroupID, 1, customergroupID, A, 198, , , , BTREE, , 
    requests, 1, userID, 1, userID, A, 1848, , , YES, BTREE, , 
    requests, 1, siteID, 1, siteID, A, 381, , , YES, BTREE, , 
    requests, 1, request, 1, subject, , 1, , , YES, FULLTEXT, , 
    requests, 1, request, 2, detail, , 1, , , YES, FULLTEXT, , 
    requests, 1, request, 3, ponumber, , 1, , , YES, FULLTEXT, , 

Répondre

3

Une recherche LIKE passera par tous les enregistrements et effectuer la comparaison des chaînes non-exacte, qui C'est pourquoi c'est si lent. L'erreur mysql que vous avez collée indique que la colonne référencée dans la clause MATCH n'a pas d'index de texte intégral (ou c'est le cas, mais ce n'est pas comme cela est référencé dans la clause MATCH).

En supposant que vous utilisez MyISAM ou avez MySQL 5.6 et InnoDB, essayez:

ALTER TABLE responses ADD FULLTEXT(response); 

Edit: Réponse (dans les commentaires): «S'il y a deux colonnes mentionnées dans l'instruction MATCH, il devrait y être un index fulltext sur ces deux colonnes, pas deux index fulltext sur chaque colonne "

+0

Merci, j'ai essayé mais cela n'a pas résolu le problème. J'ai modifié mon message original. Le fait est que la recherche LIKE prend la moitié du temps que la recherche MATCH ... AGAINST effectue cependant je suppose qu'en optimisant/améliorant cette dernière, elle pourrait être beaucoup plus rapide que la recherche LIKE. Ai-je raison? – Pawel

+0

Que se passe-t-il lorsque vous essayez simplement: SELECT * FROM réponses WHERE MATCH (réponse) AGAINST ('twisted') Si cela ne fonctionne pas, essayez: ALTER TABLE réponses de table ENABLE KEYS Si cela ne fonctionne pas, le problème est pas avec l'index fulltext, mais dans le chemin/ordre que vous avez écrit la requête. –

+0

Merci, j'ai modifié mon message original avec les requêtes et les résultats. – Pawel