2012-11-14 30 views
7

我在Firebird中查詢的速度有問題。緩慢是在分類和獨特。查詢firebird慢速排序/ distinct

如果我在MySQL中嘗試查詢,那麼他的速度會快一秒。

火鳥 - > 1,3s一個1,6s 的MySQL - > 0,3s一個0,4s

我們使用Firebird數據庫Web服務器/網站,所以速度是非常重要的。

規格: - 火鳥2.5.1或2.5.2(SuperClassic)64位 - 2,13千兆赫(2個處理器) - RAM 4,00 GB

該怎麼辦?

我有以下表格:

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

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

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

查詢在火鳥:

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 

查詢在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; 

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

我有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 

謝謝!

+0

什麼是tree3?您列出了文章3_1表格兩次。 – nater

+0

對不起,我添加了兩次相同的元數據。 – VanderLinde

回答

0

這可能有點老了,但希望仍然可以幫助。

一般來說,按操作區分和排序需要排序。排序是由索引幫助。考慮爲按子句順序指定的列創建索引 - NodePosition,我可以看到的唯一其他索引是與另一列合成的,這樣索引就不會被順序依次查閱。對於不同的,你可以嘗試創建一個tr.IdLink,tr.IdTargetLink,tr.IdItem,tr.NodePosition列或每個單獨的組合索引。 (我不太確定索引有多大幫助,但值得一試)。

要考慮的其他事項:您的where子句使用函數 - 在此上下文中使用函數時將導致全表掃描,甚至可能不會查看您的索引。我不相信mySql支持基於函數的索引,不確定FireBird。但是可以通過創建另一個可以保存LOWER(列)結果的列來解決問題,如果可用,您需要使用觸發器維護該列。

或條件和LIKE'%a4%'也將導致全表掃描。我意識到您的業務邏輯可能不允許您從'%a4%'字符串的開頭刪除通配符字符以便可能改進這種用例,您可以考慮子查詢 - 首先嚐試縮小結果集的範圍可能在子查詢中避免任何LIKE或OR,然後用父查詢包裝該結果,這將進一步過濾結果(將子查詢放入FROM子句中)。所以在你的子查詢中,你會有這些條件:tr.ItemType = 2 AND tr.Market1 = 1 and tr.NODELEVEL = 5 and tr。LINKTYPE <> 5

+0

是的,Firebird 2+允許在表達式/函數上使用索引:http://www.firebirdsql.org/refdocs/langrefupd20-create-index.html#langrefupd20-creatind-on-expr – reiniero

1

業避免DISTINCT和LIKE如果可以的話, DISTINCT優化​​ http://dev.mysql.com/doc/refman/5.0/en/distinct-optimization.html

通過,而不是不同的嘗試與A組嵌套查詢。我用這個來解決這個問題時使用group by & order by。

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

而且我看不到你的表引擎,但MyISAM的是全文搜索(而不是InnoDB的)更好。此外,可能值得一看Solr進行全文搜索。有點學習曲線可以設置,但是你可以索引mysql表,然後在多個列上執行部分匹配搜索。隨着提升和迷人的事情。

查看下面的查詢是否有任何性能優勢。

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;