2015-10-21 20 views
6

Io lavoro su un sito web in esecuzione su Propel e ho questa domanda:MySQL Partita ... Contro di query molto lenta

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); 
} 

che si traduce al seguente in 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 

E ' richiede un buon 20 secondi per caricare sul sito web utilizzando Propel e 7.020 secondi quando si esegue la query SQL.

Ho provato il seguente invece:

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 

che richiede 3.308 secondi per eseguire. La rimozione di OR Response.response LIKE '%46104%' da esso riduce il tempo a 0,140 secondi. La tabella delle risposte contiene 288317 righe e la colonna responses.responses è una colonna TEXT() con un indice FULLTEXT.

Quale sarebbe il modo migliore per ridurre il tempo di esecuzione di questa ricerca? Ho provato con questa https://dba.stackexchange.com/questions/15214/why-is-like-more-than-4x-faster-than-match-against-on-a-fulltext-index-in-mysq risposta tuttavia quando eseguo:

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

ottengo questo errore:

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

aiuto sarà molto apprezzato!

EDIT 1:

provato domanda di @pluto EB:

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

Tuttavia:

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 

Rimozione DISTINCT riduce il tempo di esecuzione di 0,952 secondi tuttavia non recupera i risultati di cui ho bisogno.

EDIT 2:

che esegue la query:

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

prende 0,062 secondi.

L'esecuzione di questo:

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

richiede solo 0,046 secondi. Tuttavia, selezionare da Richieste e unire le risposte è ciò che rallenta la query. Non sono sicuro che ciò significhi che l'intera query deve essere completamente riscritta per selezionare da Risposte e unire Richieste invece?

EDIT 3:

Qui ci sono gli indici che ho sul Requests e Responses tabelle:

# 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, , 

risposta

3

una ricerca come passerà attraverso ogni record ed eseguire non esatto confronto tra stringhe, che è il motivo per cui è così lento.

L'errore mysql che hai incollato indica che la colonna a cui si fa riferimento nella clausola MATCH non ha un indice di fulltext (o lo fa, ma non è come si fa riferimento nella clausola MATCH).

Supponendo che si sta utilizzando MyISAM o hanno MySQL 5.6 e InnoDB, provare:

ALTER TABLE responses ADD FULLTEXT(response); 

Edit: Risposta (nei commenti): "Se ci sono due colonne parte dell'autore di operatori PARTITA, allora non ci dovrebbero essere un indice di testo completo su entrambe le colonne, non due indici di testo completo su ogni colonna "

+0

Grazie, ho provato che tuttavia non ha risolto il problema. Ho modificato il mio post originale. Il fatto è che la ricerca LIKE impiega la metà del tempo che la ricerca MATCH ... CONTRO fa tuttavia suppongo che ottimizzando/migliorando quest'ultimo, potrebbe essere molto più veloce della ricerca LIKE. Ho ragione? – Pawel

+0

Cosa succede quando si prova solo: SELECT * FROM risposte WHERE MATCH (risposta) CONTRO ('intrecciato') Se ciò non funziona, provare: ALTER TABLE risposte della tabella ENABLE KEYS Se funziona, il problema è non con l'indice di testo completo, ma nel modo/nell'ordine in cui hai scritto la query. –

+0

Grazie, ho modificato il mio post originale con le query e i risultati. – Pawel