4

テーブルが完全に入力されると、以下のクエリのパフォーマンスが心配になります。これまでのところ開発中であり、ダミーデータでうまく機能します。

テーブル「adress_zoo」には、完全に入力されると約5億件のレコードが含まれます。「adress_zoo」テーブルは次のようになります。

  CREATE TABLE `adress_zoo` 
     ( `adress_id` int(11) NOT NULL, `zoo_id` int(11) NOT NULL, 
     UNIQUE KEY `pk` (`adress_id`,`zoo_id`), 
     KEY `adress_id` (`adress_id`) ) 
     ENGINE=InnoDB DEFAULT CHARSET=latin1;

他のテーブルには、それぞれ最大500レコードが含まれます。

完全なクエリは次のようになります。

  SELECT a.* FROM jos_zoo_item AS a 
  JOIN jos_zoo_search_index AS zsi2 ON zsi2.item_id = a.id 
  WHERE a.id IN (   

     SELECT r.id FROM ( 

        SELECT zi.id AS id, Max(zi.priority) as prio 
        FROM jos_zoo_item AS zi 
        JOIN jos_zoo_search_index AS zsi ON zsi.item_id = zi.id 
        LEFT JOIN jos_zoo_tag AS zt ON zt.item_id = zi.id 
        JOIN jos_zoo_category_item AS zci ON zci.item_id = zi.id 
        **JOIN adress_zoo AS az ON az.zoo_id = zi.id** 

        WHERE 1=1 
        AND ( (zci.category_id != 0 AND ( zt.name != 'prolong' OR zt.name is NULL)) 
        OR (zci.category_id = 0 AND zt.name = 'prolong') ) 
        AND zi.type = 'telefoni' 
        AND zsi.element_id = '44d3b1fd-40f6-4fd7-9444-7e11643e2cef' 
        AND zsi.value = 'Small' 
        AND zci.category_id > 15 
        **AND az.adress_id = 5** 

        GROUP BY zci.category_id ) AS r 
  ) 

  AND a.application_id = 6 
  AND a.access IN (1,1) 
  AND a.state = 1 
  AND (a.publish_up = '0000-00-00 00:00:00' OR a.publish_up <= '2012-06-07 07:51:26') 
  AND (a.publish_down = '0000-00-00 00:00:00' OR a.publish_down >= '2012-06-07 07:51:26') 
  AND zsi2.element_id = '1c3cd26e-666d-4f8f-a465-b74fffb4cb14' 

  GROUP BY a.id 
  ORDER BY zsi2.value ASC

クエリは通常、約25レコードを返します。

あなたの経験に基づいて、このクエリは許容範囲内で実行されますか(たとえば3秒以内に応答します)?これを最適化するにはどうすればよいですか?

@Jackのアドバイスに従って、EXPLAINを使用してクエリを実行し、次のようにしました。

MySQLEXPLAIN出力

4

2 に答える 2

2

この部分は重要なリミッターです。

az.adress_id = 5

MySQLは、テーブルをステートメントの残りの部分と結合する前adress_idに一致するレコードのみに制限するため、結果セットの大きさによって異なります。

ところで、あなたはUNIQUE(adress_id, zoo_id)と別のものを持っていますINDEX。特別な理由はありますか?スパニングキーの最初の部分は、MySQLでも選択できるためです。

また重要なのは、EXPLAINMySQLがクエリを「攻撃」して結果を返す方法を理解するために使用することです。参照:http ://dev.mysql.com/doc/refman/5.5/en/execution-plan-information.html

于 2012-06-07T08:41:30.913 に答える
0

サブクエリを回避するには、クエリを次のように書き直してみてください。

SELECT a.* FROM jos_zoo_item AS a 
  JOIN jos_zoo_search_index AS zsi2 ON zsi2.item_id = a.id 
  INNER JOIN 
  (   
     SELECT ** distinct ** r.id FROM ( 

        SELECT zi.id AS id, Max(zi.priority) as prio 
        FROM jos_zoo_item AS zi 
        JOIN jos_zoo_search_index AS zsi ON zsi.item_id = zi.id 
        LEFT JOIN jos_zoo_tag AS zt ON zt.item_id = zi.id 
        JOIN jos_zoo_category_item AS zci ON zci.item_id = zi.id 
        **JOIN adress_zoo AS az ON az.zoo_id = zi.id** 

        WHERE 1=1 
        AND ( (zci.category_id != 0 AND ( zt.name != 'prolong' OR zt.name is NULL)) 
        OR (zci.category_id = 0 AND zt.name = 'prolong') ) 
        AND zi.type = 'telefoni' 
        AND zsi.element_id = '44d3b1fd-40f6-4fd7-9444-7e11643e2cef' 
        AND zsi.value = 'Small' 
        AND zci.category_id > 15 
        **AND az.adress_id = 5** 

        GROUP BY zci.category_id ) AS r 
  ) T
    on a.id = T.id
  where 
  AND a.application_id = 6 
  AND a.access IN (1,1) 
  AND a.state = 1 
  AND (a.publish_up = '0000-00-00 00:00:00' OR a.publish_up <= '2012-06-07 07:51:26') 
  AND (a.publish_down = '0000-00-00 00:00:00' OR a.publish_down >= '2012-06-07 07:51:26') 
  AND zsi2.element_id = '1c3cd26e-666d-4f8f-a465-b74fffb4cb14' 

  GROUP BY a.id 
  ORDER BY zsi2.value ASC

このアプローチでは、候補行ごとにサブクエリを実行しません。Tが数ミリ秒で計算された場合にのみ、パフォーマンスが向上する可能性があります。

于 2012-06-07T08:51:42.537 に答える