通过/ distinct查询firebird慢速顺序

时间:2012-11-14 20:47:16

标签: mysql sql performance firebird database-performance

我对Firebird中的查询速度有疑问。缓慢是在排序和不同。

如果我在MySQL中尝试查询,那么他会快一秒。

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

我们在Web服务器/网站上使用Firebird数据库,因此速度很重要。

规格: - Firebird 2.5.1或2.5.2(SuperClassic)64位 - 2,13 Ghz(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);

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

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

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

谢谢!

2 个答案:

答案 0 :(得分:1)

如果可以的话,Yip避免DISTINCT和LIKE, DISTINCT优化 http://dev.mysql.com/doc/refman/5.0/en/distinct-optimization.html

尝试使用group by而不是distinct来嵌套查询。我使用它来解决这个问题时使用group by&amp;按顺序排列。

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;

答案 1 :(得分:0)

现在可能有点老了,但希望仍然有用。

一般来说,操作的不同和顺序需要排序。排序由索引辅助。考虑为order by子句指定的列创建索引 - NodePosition,我可以看到的唯一其他索引是与另一列复合,因此订单不会查询索引。对于distinct,您可以尝试为tr.IdLink,tr.IdTargetLink,tr.IdItem,tr.NodePosition列或单独创建复合索引。 (我不太确定指数会对指数有多大帮助,但值得一试)。

要考虑的其他事项:你的where子句使用函数 - 在此上下文中使用时的函数将导致全表扫描,甚至可能不会查看索引。我不相信mySql支持基于函数的索引,不确定FireBird。但是可以通过创建另一个可以保存LOWER(列)结果的列来解决它,如果可用的话,您需要使用触发器来维护该列。

OR条件和LIKE'%a4%'也会导致全表扫描。我意识到您的业务逻辑可能不允许您从'%a4%'字符串的开头删除通配符char,以便可能改进此类用例,您可以考虑子查询 - 首先尝试缩小结果集的范围。可能在子查询中避免任何LIKE或OR,然后用父查询包装该结果,这将进一步过滤结果(将子查询放入FROM子句)。因此,在子查询中,您将具有以下条件:tr.ItemType = 2 AND tr.Market1 = 1且tr.NODELEVEL = 5且tr.LINKTYPE&lt;&gt; 5