2012-11-14 10 views
7

Ho un problema con la velocità di una query in Firebird. La lentezza è nell'ordinamento e distinto.Ordine lento di Firebird query per/distinto

Se provo la query in MySQL, è un secondo più veloce.

Firebird -> 1,3s un MySQL 1,6s -> 0,3s un 0,4s

Usiamo il database Firebird su un server web/sito web, quindi la velocità è importante.

Specifica: - Firebird 2.5.1 e 2.5.2 (Superclassic) 64 bit - 2,13 Ghz (2 processori) - RAM 4,00 GB

Cosa posso fare?

ho le seguenti tabelle:

==================================== ================

CREATE TABLE ARTICLE3_1 
(
    IDARTICLE Integer NOT NULL, 
    ITEMSTATUS Integer, 
    ITEMENTRYDATE Integer, 
    ITEMFILTER Integer, 
    ARTIKELNUMMER Varchar(250), 
    ARTIKELNAAM1 Varchar(250), 
    ARTIKELNAAM2 Varchar(250), 
    OMSCHRIJVING_DETAIL Blob sub_type 1, 
    OMSCHRIJVING1 Varchar(250), 
    OMSCHRIJVING2 Varchar(250), 
    ARTIKELNR_LEVERANCIER Varchar(250), 
    MERK Varchar(250), 
    LEVERANCIER Varchar(250), 
    EAN Varchar(250), 
    LINKAANGROEP Varchar(250), 
    LINKAANAANBIEDINGGROEP Varchar(250), 
    LINKAANPOPULAIRGROEP Varchar(250), 
    LINKAANART Varchar(250), 
    ARTGRPNR Varchar(250), 
    SUBGROEP Varchar(250), 
    PRIJSPER Integer, 
    VERKOOPPRIJS Float, 
    ADVIESPRIJS Float, 
    BTWPERC Float, 
    ONLINE Varchar(250), 
    TUSGROEPBIJLINK Varchar(250), 
    AFBEELDINGKLEIN Varchar(250), 
    AFBEELDINGMIDDEL Varchar(250), 
    AFBEELDINGGROOT Varchar(250), 
    ICECATLINK Varchar(250), 
    LINKAANHOMEPAGEGROEP Varchar(250), 
    LINKAANMIJNACCOUNTGROEP Varchar(250), 
    SORTEER Varchar(250), 
    AFBEELDING Varchar(100), 
    FLASH Blob sub_type 1, 
    EENHEID Varchar(250), 
    ALTARTNR1 Varchar(250), 
    ALTARTNR2 Varchar(250), 
    BESTELLENPER Float, 
    INFEED Varchar(250), 
    GOOGLE_TAXONOMIE Varchar(250), 
    FEED_TITEL Varchar(250), 
    FEED_OMSCHRIJVING Blob sub_type 1, 
    PRIMARY KEY (IDARTICLE) 
); 
CREATE INDEX IDX_ARTICLE3_1_2 ON ARTICLE3_1 (MERK); 
CREATE INDEX IDX_ARTICLE3_1_3 ON ARTICLE3_1 (ARTIKELNUMMER); 
CREATE INDEX IDX_ARTICLE3_1_4 ON ARTICLE3_1 (ARTIKELNR_LEVERANCIER); 
CREATE INDEX IDX_ARTICLE3_1_5 ON ARTICLE3_1 (ALTARTNR2); 
CREATE INDEX IDX_ARTICLE3_1_6 ON ARTICLE3_1 (ARTIKELNAAM1); 
CREATE INDEX IDX_ARTICLE3_1_7 ON ARTICLE3_1 (EAN); 

    CREATE TABLE TREE3 
(
    IDLINK Integer NOT NULL, 
    LINKTYPE Integer, 
    IDITEM Integer, 
    ITEMTYPE Integer, 
    IDTARGETLINK Integer, 
    NODEPOSITION Integer, 
    NODELEVEL Integer, 
    IDLAYOUTDATA Integer, 
    IDTEMPLATE Integer, 
    ACTIONDATE Integer, 
    MARKET1 Integer, 
    PRIMARY KEY (IDLINK) 
); 
CREATE INDEX IDX_TREE3_2 ON TREE3 (IDITEM); 
CREATE INDEX IDX_TREE3_3 ON TREE3 (MARKET1); 
CREATE INDEX ITREE13 ON TREE3 (IDTARGETLINK,NODEPOSITION); 
CREATE INDEX ITREE53 ON TREE3 (IDITEM,ITEMTYPE); 

==================================================== 

la query in FireBird:

SELECT FIRST 30 SKIP 0 distinct tr.IdLink, tr.IdTargetLink, tr.IdItem, tr.NodePosition 
FROM Tree3 tr 
inner join article3_1 art on art.idarticle = Tr.iditem 
WHERE tr.ItemType = 2 AND tr.Market1 = 1 
AND ((art.IDARTICLE > 0) AND ( (LOWER(art.Artikelnummer) like '%a4 papier%') OR ((LOWER(art.Artikelnummer) like 'a4') 
AND (LOWER(art.Artikelnummer) like 'papier')) OR (LOWER(art.Artikelnaam1) like '%a4 papier%') OR ((LOWER(art.Artikelnaam1) like '%a4%') 
AND (LOWER(art.Artikelnaam1) like '%papier%')) OR (LOWER(art.Artikelnaam2) like '%a4 papier%') OR ((LOWER(art.Artikelnaam2) like '%a4%') 
AND (LOWER(art.Artikelnaam2) like '%papier%')) OR (LOWER(art.Artikelnr_leverancier) like '%a4 papier%') OR ((LOWER(art.Artikelnr_leverancier) like '%a4%') 
AND (LOWER(art.Artikelnr_leverancier) like '%papier%')) OR (LOWER(art.Merk) like '%a4 papier%') OR ((LOWER(art.Merk) like '%a4%') 
AND (LOWER(art.Merk) like '%papier%')) OR (LOWER(art.EAN) like '%a4 papier%') OR ((LOWER(art.EAN) like '%a4%') 
AND (LOWER(art.EAN) like '%papier%')) OR (LOWER(art.AltArtnr1) like '%a4 papier%') OR ((LOWER(art.AltArtnr1) like '%a4%') 
AND (LOWER(art.AltArtnr1) like '%papier%')) OR (LOWER(art.AltArtnr2) like '%a4 papier%') OR ((LOWER(art.AltArtnr2) like '%a4%') 
AND (LOWER(art.AltArtnr2) like '%papier%')))) 
AND tr.NODELEVEL =5 and tr.LINKTYPE <> 5 
ORDER BY tr.NodePosition 

la query in MySQL:

SELECT distinct tr.IdLink, tr.IdTargetLink, tr.IdItem, tr.NodePosition 
FROM Tree3 tr 
inner join article3_1 art on art.idarticle = Tr.iditem 
WHERE tr.ItemType = 2 AND tr.Market1 = 1 
AND ((art.IDARTICLE > 0) AND ( (LCASE(art.Artikelnummer) like '%a4 papier%') OR ((LCASE(art.Artikelnummer) like 'a4') 
AND (LCASE(art.Artikelnummer) like 'papier')) OR (LCASE(art.Artikelnaam1) like '%a4 papier%') OR ((LCASE(art.Artikelnaam1) like '%a4%') 
AND (LCASE(art.Artikelnaam1) like '%papier%')) OR (LCASE(art.Artikelnaam2) like '%a4 papier%') OR ((LCASE(art.Artikelnaam2) like '%a4%') 
AND (LCASE(art.Artikelnaam2) like '%papier%')) OR (LCASE(art.Artikelnr_leverancier) like '%a4 papier%') OR ((LCASE(art.Artikelnr_leverancier) like '%a4%') 
AND (LCASE(art.Artikelnr_leverancier) like '%papier%')) OR (LCASE(art.Merk) like '%a4 papier%') OR ((LCASE(art.Merk) like '%a4%') 
AND (LCASE(art.Merk) like '%papier%')) OR (LCASE(art.EAN) like '%a4 papier%') OR ((LCASE(art.EAN) like '%a4%') 
AND (LCASE(art.EAN) like '%papier%')) OR (LCASE(art.AltArtnr1) like '%a4 papier%') OR ((LCASE(art.AltArtnr1) like '%a4%') 
AND (LCASE(art.AltArtnr1) like '%papier%')) OR (LCASE(art.AltArtnr2) like '%a4 papier%') OR ((LCASE(art.AltArtnr2) like '%a4%') 
AND (LCASE(art.AltArtnr2) like '%papier%')))) 
AND tr.NODELEVEL =5 and tr.LINKTYPE <> 5 
ORDER BY tr.NodePosition LIMIT 30; 

================================================= ===

ho la query eseguita con FlameRobin:

> Prepare time: 0.016s Field #01: TREE3.IDLINK Alias:IDLINK Type:INTEGER 
> Field #02: TREE3.IDTARGETLINK Alias:IDTARGETLINK Type:INTEGER Field 
> #03: TREE3.IDITEM Alias:IDITEM Type:INTEGER Field #04: TREE3.NODEPOSITION Alias:NODEPOSITION Type:INTEGER PLAN SORT (SORT 
> (JOIN (TR INDEX (IDX_TREE3_2, IDX_TREE3_3), ART INDEX 
> (RDB$PRIMARY2)))) 
> 
> 873424 fetches, 0 marks, 12892 reads, 0 writes. 0 inserts, 0 updates, 
> 0 deletes, 380580 index, 0 seq. Delta memory: 1784 bytes. Total 
> execution time: 1.311s 

Grazie!

+0

Cos'è tree3? Hai elencato la tabella article3_1 due volte. – nater

+0

Siamo spiacenti, ho aggiunto due volte gli stessi metadati. – VanderLinde

risposta

0

Questo potrebbe essere un po 'vecchio ora, ma si spera possa ancora essere utile.

In generale, distinti e ordinati per operazioni richiedono un ordinamento. I tipi sono aiutati da indici. Prendi in considerazione la creazione di indici per le colonne specificate in ordine per clausola - NodePosition, l'unico altro indice su di esso che posso vedere è composto da un'altra colonna in modo che l'indice non venga consultato dall'ordine per. Per il distinto, si può provare a creare un indice composito per tr.IdLink, tr.IdTargetLink, tr.IdItem, colonne tr.NodePosition o singolarmente. (Non sono troppo sicuro di quanto sarebbe distinto dagli indici, ma vale la pena provarlo).

Altre cose da considerare: la clausola where utilizza le funzioni - le funzioni se utilizzate in questo contesto generano scansioni complete della tabella e potrebbero anche non guardare gli indici. Non credo che mySql supporti indici basati su funzioni, non sono sicuro di FireBird. Ma può essere aggirato creando un'altra colonna che possa contenere il risultato del LOWER (colonna), sarebbe necessario mantenere quella colonna usando i trigger, se disponibili.

O condizione e LIKE '% a4%' comporterà anche scansioni complete della tabella. Mi rendo conto che la tua logica aziendale potrebbe non consentire di eliminare il carattere jolly dall'inizio della stringa '% a4%' in modo da migliorare eventualmente tali casi d'uso, potresti prendere in considerazione le subquery: prima prova a restringere il tuo set di risultati tanto quanto possibile nella sottoquery evitando qualsiasi LIKE o OR e quindi avvolgere quel risultato con una query genitore che filtrerà ulteriormente i risultati (mettendo subquery nella clausola FROM). Quindi nella tua subquery, avresti queste condizioni: tr.ItemType = 2 AND tr.Market1 = 1 e tr.NODELEVEL = 5 e tr.LINKTYPE <> 5

+0

Sì, Firebird 2+ consente gli indici su espressioni/funzioni: http://www.firebirdsql.org/refdocs/langrefupd20-create-index.html#langrefupd20-creatind-on-expr – reiniero

1

Yip evitare DISTINCT e, come se è possibile, ottimizzazione DISTINCT http://dev.mysql.com/doc/refman/5.0/en/distinct-optimization.html

Prova una query nidificate con il gruppo dal posto di distinte. Io uso questo per aggirare il problema quando si usa il gruppo per ordine &.

select * from ({the rest of the query}) as some_table group by {my distinct column};

Inoltre non riesco a vedere il vostro motore tavolo, ma MyISAM è meglio per la ricerca di testo completo (piuttosto che InnoDB). Potrebbe anche valere la pena guardare Solr per la ricerca a testo integrale. Un po 'di una curva di apprendimento da configurare, ma è possibile indicizzare tabelle mysql e quindi eseguire ricerche di corrispondenze parziali su più colonne. Con cose come amplificazione e meraviglia.

Vedere se la query seguente presenta dei vantaggi in termini di prestazioni.

select * from (SELECT tr.IdLink, tr.IdTargetLink, tr.IdItem, tr.NodePosition 
FROM Tree3 tr 
inner join article3_1 art on art.idarticle = Tr.iditem 
WHERE tr.ItemType = 2 AND tr.Market1 = 1 
AND ((art.IDARTICLE > 0) AND ( (LCASE(art.Artikelnummer) like '%a4 papier%') OR (
(LCASE(art.Artikelnummer) like 'a4') 
AND (LCASE(art.Artikelnummer) like 'papier')) OR (LCASE(art.Artikelnaam1) like '%a4 papier%') OR ((LCASE(art.Artikelnaam1) like '%a4%') 
AND (LCASE(art.Artikelnaam1) like '%papier%')) OR (LCASE(art.Artikelnaam2) like '%a4 papier%') OR ((LCASE(art.Artikelnaam2) like '%a4%') 
AND (LCASE(art.Artikelnaam2) like '%papier%')) OR (LCASE(art.Artikelnr_leverancier) 
like '%a4 papier%') OR ((LCASE(art.Artikelnr_leverancier) like '%a4%') 
AND (LCASE(art.Artikelnr_leverancier) like '%papier%')) OR (LCASE(art.Merk) like '%a4 papier%') OR ((LCASE(art.Merk) like '%a4%') 
AND (LCASE(art.Merk) like '%papier%')) OR (LCASE(art.EAN) like '%a4 papier%') OR (
(LCASE(art.EAN) like '%a4%') 
AND (LCASE(art.EAN) like '%papier%')) OR (LCASE(art.AltArtnr1) like '%a4 papier%') OR  
((LCASE(art.AltArtnr1) like '%a4%') 
AND (LCASE(art.AltArtnr1) like '%papier%')) OR (LCASE(art.AltArtnr2) like '%a4 papier%') OR ((LCASE(art.AltArtnr2) like '%a4%') 
AND (LCASE(art.AltArtnr2) like '%papier%')))) 
AND tr.NODELEVEL =5 and tr.LINKTYPE <> 5 
ORDER BY tr.NodePosition LIMIT 30) 
as some_table group by IdLink;