7

Firebirdでのクエリの速度に問題があります。遅さは分類と明確にあります。

MySQLでクエリを試してみると、彼は1秒速くなっています。

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

Webサーバー/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

ありがとうございました!

4

2 に答える 2

1

できれば DISTINCT と LIKE を避けてください。 DISTINCT 最適化 http://dev.mysql.com/doc/refman/5.0/en/distinct-optimization.html

個別の代わりに group by を使用して、ネストされたクエリを試してください。これを使用して、group by と order by を使用する際の問題を回避します。

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

また、テーブル エンジンが表示されませんが、全文検索には (InnoDB よりも) MyIsam の方が優れています。また、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;
于 2012-12-28T00:49:57.217 に答える
0

これは今では少し古いかもしれませんが、うまくいけばまだ役に立ちます。

一般的に言えば、distinct 操作と order by 操作には並べ替えが必要です。並べ替えは、インデックスによって支援されます。order by句で指定された列のインデックスを作成することを検討してください-NodePosition、私が見ることができる唯一の他のインデックスは、別の列との複合であるため、インデックスはorder byによって参照されません。個別の場合は、tr.IdLink、tr.IdTargetLink、tr.IdItem、tr.NodePosition 列、またはそれぞれ個別に複合インデックスを作成してみてください。(インデックスによってどの程度の違いが得られるかについてはよくわかりませんが、試してみる価値があります)。

その他の考慮事項: where 句で関数が使用されている - このコンテキストで関数を使用すると、テーブル全体がスキャンされ、インデックスが表示されない場合があります。mySql が関数ベースのインデックスをサポートしているとは思えません。FireBird についてはわかりません。ただし、LOWER(column) の結果を保持できる別の列を作成することで回避できます。可能であれば、トリガーを使用してその列を維持する必要があります。

OR 条件と LIKE '%a4%' もテーブル全体のスキャンになります。あなたのビジネス ロジックでは、'%a4%' 文字列の先頭からワイルドカード文字を削除できない可能性があるため、このようなユース ケースを改善するために、サブクエリを検討してください。サブクエリで LIKE または OR を回避し、その結果を親クエリでラップして、結果をさらにフィルタリングします (サブクエリを FROM 句に入れます)。したがって、サブクエリには次の条件があります: tr.ItemType = 2 AND tr.Market1 = 1 and tr.NODELEVEL =5 and tr.LINKTYPE <> 5

于 2012-12-04T23:08:52.980 に答える