2012-05-03 9 views
0

私はPDO Mysqlを使用して、私のデータベース内の製品に対して最も安いオファーを選択するように要求しました。それはうまく動作し、問題はそれだけでは遅いです(200回の申し込みで(しかも25回も戻ってくるまで))、それは私が目指すものよりもはるかに高い、ほぼ1秒かかります。SQLリクエストを最適化

私はSQLの専門家ではないので、私はこの問題についてあなたの助けを求めます。ここで要求され、必要に応じて、私はより多くの情報を提供させていただきます:

SELECT 
      mo.id AS id, 
      mo.stock AS stock, 
      mo.price AS price, 
      mo.promotional_price AS promotional_price, 
      mo.picture_1 AS picture_1, 
      mo.picture_2 AS picture_2, 
      mo.picture_3 AS picture_3, 
      mo.picture_4 AS picture_4, 
      mo.picture_5 AS picture_5, 
      mo.title AS title, 
      mo.description AS description, 
      mo.state AS state, 
      mo.is_new AS is_new, 
      mo.is_original AS is_original, 
      c.name AS name, 
      u.id AS user_id, 
      u.username AS username, 
      u.postal_code AS postal_code, 
      p.name AS country_name, 
      ra.cache_rating_avg AS cache_rating_avg, 
      ra.cache_rating_nb AS cache_rating_nb, 
      GROUP_CONCAT(md.delivery_mode_id SEPARATOR ', ') AS delivery_mode_ids, 
      GROUP_CONCAT(ri.title SEPARATOR ', ') AS delivery_mode_titles 

     FROM 
      mp_offer mo, catalog_product_i18n c, 
      ref_country_i18n p, mp_offer_delivery_mode md, 
      ref_delivery_mode r, 
      ref_delivery_mode_i18n ri, user u 

     LEFT JOIN mp_user_review_rating_i18n ra 
      ON u.id = ra.user_id 

     WHERE (mo.product_id = c.id 
       AND mo.culture = c.culture 
       AND mo.user_id = u.id 
       AND u.country_id = p.id 
       AND mo.id = md.offer_id 
       AND md.delivery_mode_id = ri.id 
       AND mo.culture = ri.culture) 
      AND (mo.culture = 1 
       AND p.culture = 1) 
      AND mo.is_deleted = 0 
      AND mo.product_id = 60 
      AND ((u.holiday_start IS NULL) 
       OR (u.holiday_start = '0000-00-00') 
       OR (u.holiday_end IS NULL) 
       OR (u.holiday_end = '0000-00-00') 
       OR (u.holiday_start > '2012-05-03') 
       OR (u.holiday_end < '2012-05-03')) 
      AND mo.stock > 0 
     GROUP BY mo.id 
     ORDER BY IF (mo.promotional_price IS NULL, 
        mo.price, 
        LEAST(mo.price, mo.promotional_price)) ASC 

     LIMIT 25 OFFSET 0; 

は私が1に設定され、その「文化」を持っている特定の製品のためのオファーを取る、いくつかの株式を持っている、削除されませんその売り手は休日ではありません。私は価格で注文します(1つがある場合はプロモーション価格)。

LEASTは遅い機能ですか?ここで

はEXPLAINの出力は次のようになります。この要求を最適化する上で、あなたの助けを事前に

id select_type table type possible_keys                  key  key_len ref         rows Extra 
1 SIMPLE  c  const PRIMARY,catalog_product_i18n_product,catalog_product_i18n_culture     PRIMARY 8  const,const       1  "Using temporary; Using filesort" 
1 SIMPLE  mo  ref  PRIMARY,culture,is_deleted,product_id,user_id          culture 4  const        3  "Using where with pushed condition" 
1 SIMPLE  u  eq_ref PRIMARY,user_country                PRIMARY 4  database.mo.user_id     1  "Using where with pushed condition" 
1 SIMPLE  p  eq_ref PRIMARY,ref_country_i18n_culture             PRIMARY 8  database.u.country_id,const   1 
1 SIMPLE  r  ALL  NULL                    NULL NULL NULL        3  "Using join buffer" 
1 SIMPLE  ra  ALL  NULL                    NULL NULL NULL        4 
1 SIMPLE  md  ref  PRIMARY,fk_offer_has_delivery_mode_delivery_mode1,fk_offer_has_delivery_mode_offer1 PRIMARY 4  database.mo.id      2 
1 SIMPLE  ri  eq_ref PRIMARY                    PRIMARY 2  database.md.delivery_mode_id,const 1 

感謝。

J

+0

最初に説明とあなたのスキーマを表示 – zerkms

+1

JOIN IDに索引を追加することから始めます(まだPRIMARYに設定されていない場合)。 –

+0

すでにPRIMARYに設定されています。私は説明の出力で私の質問を編集 – user1372006

答えて

0

あなたはFROM句で含まれているref_delivery_modeテーブルを利用していません。テーブル結果のデカルト積の原因となっています。

+0

カントは、クエリの残りの部分でテーブルへの参照を見つける。よく目撃された。 – Namphibian

+0

はい、私はあなたの返信の数秒前に気付いた。私はそれを使用していたが、私はもはやいない。その行を削除すると、リクエストで150msのようなものが得られました。それは良いスタートです、あまりにも悪い私は無駄な線はありません! – user1372006

+0

sqlからorder by句を削除します。これは、すべてのレコードをフェッチしてから順番を適用し、25レコードだけを表示するためです。 –