2012-11-14 5 views
7

Mam problem z szybkością zapytania w Firebird. Powolność jest w sortowaniu i odrębna.Zapytanie o powolne zamówienie firebirda przez/odrębne

Jeśli wypróbuję zapytanie w MySQL, to jest o sekundę szybszy.

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

Używamy Firebird bazy danych na serwerze WWW/stronie internetowej, więc prędkość jest ważna.

Specyfikacja: - Firebird 2.5.1 i 2.5.2 (SuperClassic) 64 bitów - 2,13 GHz (2 procesory) - RAM 4,00 PL

co można zrobić?

mam następujące tabele:

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

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

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

Query w 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 

zapytań w 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; 

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

mam zapytanie wykonany z 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 

dziękuję!

+0

Co to jest tree3? Dwukrotnie umieściłeś tabelę article3_1. – nater

+0

Niestety, miałem dwa razy te same metadane dodane. – VanderLinde

Odpowiedz

0

Może to być nieco stary, ale miejmy nadzieję, że nadal może być pomocne.

Ogólnie rzecz biorąc, odrębne i uporządkowane według operacji wymagają sortowania. Sortowania są wspomagane przez indeksy. Rozważ utworzenie indeksów dla kolumn określonych w kolejności według klauzuli - NodePosition, jedyny inny indeks na tym, jaki widzę, jest złożony z inną kolumną, tak że nie jest on konsultowany przez zamówienie przez. Dla różnych możesz spróbować utworzyć indeks złożony dla kolumn tr.IdLink, tr.IdTargetLink, tr.IdItem, tr.NodePosition lub indywidualnie. (Nie jestem pewien, na ile wyraźniej pomógłby indeks, ale warto spróbować).

Inne kwestie do rozważenia: klauzula where używa funkcji - funkcje używane w tym kontekście spowodują pełne skanowanie tabeli i mogą nawet nie patrzeć na indeksy. Nie wierzę, że mySql obsługuje indeksy oparte na funkcjach, nie ma pewności co do FireBird. Ale można go obejść, tworząc kolejną kolumnę, która może pomieścić wynik LOWER (kolumna), musisz zachować tę kolumnę za pomocą wyzwalaczy, jeśli są dostępne.

Warunek LUB LIKA "% a4%" spowoduje również pełne skanowanie tabeli. Zdaję sobie sprawę, że logika biznesowa może nie pozwolić na upuszczenie znaku wieloznacznego od początku ciągu "% a4%", aby ewentualnie poprawić takie przypadki użycia, można rozważyć podzapytania - najpierw spróbuj zawęzić zestaw wyników tak bardzo, jak możliwe w podzapytaniu unikając jakiegokolwiek LIKE lub OR, a następnie zawijając ten wynik z zapytaniem nadrzędnym, które będzie dalej filtrować wyniki (umieszczając podzapytanie w klauzuli FROM). Tak więc w twoim podzapytaniu masz te warunki: tr.ItemType = 2 AND tr.Market1 = 1 i tr.NODELEVEL = 5 i tr.LINKTYPE <> 5

+0

Tak, Firebird 2+ umożliwia indeksowanie wyrażeń/funkcji: http://www.firebirdsql.org/refdocs/langrefupd20-create-index.html#langrefupd20-creatind-on-expr – reiniero

1

Yip uniknąć odrębne i jak jeśli można, DISTINCT Optymalizacja http://dev.mysql.com/doc/refman/5.0/en/distinct-optimization.html

Spróbuj zagnieżdżone zapytania z grupy, a nie odrębne. Używam tego, aby obejść problem przy korzystaniu z grupy według numeru & według.

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

Również nie widzę silnika stołowego, ale MyISAM jest lepsze dla pełnego przeszukiwania tekstu (zamiast InnoDB). Warto również przyjrzeć się Solrowi w poszukiwaniu pełnotekstowego tekstu. Trochę krzywej uczenia się do skonfigurowania, ale możesz indeksować tabele mysql, a następnie przeprowadzić częściowe wyszukiwanie w wielu kolumnach. Z rzeczami takimi jak pobudzanie i wspaniałość.

Sprawdź, czy poniższe zapytanie nie przynosi żadnych korzyści wydajności.

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;