0

elementクエリに一致するものを収集するサイトの検索クエリを実行しています。itemsただし、にリンクされているものが1つ以上ある場合とない場合がありelementます。itemsしたがって、にリンクされているすべての一致をカウントするサブクエリがありelementます。

このクエリは機能します。しかし、信じられないほどゆっくり。現時点では約50秒かかります。サブクエリを破棄すると、はるかに高速になります。

SELECT DISTINCT e.id, 
    MATCH (e.heading) AGAINST ('+(room)') AS h_score, 
    MATCH (e.text) AGAINST ('+(room)') AS t_score, 
    ( 
        SELECT SUM( MATCH (item.heading, item.text) AGAINST ('+(room)') ) AS itemscore 
             FROM item LEFT JOIN _element_item ON item.id = _element_item.item_id 
             WHERE _element_item.item_id = e.id 
             AND MATCH (item.heading, item.text) AGAINST ('+(room)')
    ) AS i_score 

    FROM element AS e 
    LEFT JOIN _element_brand ON e.id = _element_brand.element_id 
    LEFT JOIN _element_language ON e.id = _element_language.element_id 
    LEFT JOIN _element_region ON e.id = _element_region.element_id 
    LEFT JOIN _element_type ON e.id = _element_type.element_id 
    LEFT JOIN _element_group ON e.id = _element_group.element_id     

    WHERE _element_brand.brand_id = 1 
    AND _element_language.language_iso = 'en' 
    AND _element_region.region_id = 1 
    AND _element_type.type_id = 1 
    AND _element_group.group_id = 1 
    AND e.replacement_id IS NULL 
    AND e.status = 1 
    AND MATCH (e.heading, e.text) AGAINST ('+(room)') 
    ORDER BY t_score + h_score DESC LIMIT 100

これをより速く実行する方法はありますか?

elementに一致する前に、すべてに対して完全なサブクエリを実行していると思います。element親クエリの一致に対してのみサブクエリを実行するようにできますか?もしそうなら、どのように?

4

1 に答える 1

0

サンプル シナリオの左結合を明確にしてみましょう。

select e.heading
   FROM element AS e
           LEFT JOIN _element_brand 
              ON e.id = _element_brand.element_id 
   WHERE 
          e.SomeColumn = 'test'
      AND _element_brand.brand_id = 1 

と同じことです

select e.heading
   FROM element AS e
           JOIN _element_brand 
              ON e.id = _element_brand.element_id 
   WHERE 
          e.SomeColumn = 'test'
      AND _element_brand.brand_id = 1 

WHERE 句は、一致する _element_brand レコードとそのレコードの brand_id = 1 を持つレコードのみを返すように強制されているためです。したがって、これは、「e.SomeColumn = 'test'」と brand_id = 1 のレコードのみを返します。

さて、真の左結合を見てください

select e.heading
   FROM element AS e
           LEFT JOIN _element_brand 
              ON e.id = _element_brand.element_id 
             AND _element_brand.brand_id = 1 
   WHERE 
      e.SomeColumn = 'test'

これは、_element_Brand テーブルにエントリがあり、_element_brand.brand_id = 1 であるにもかかわらず、"e.SomeColumn = 'test'" を持つ要素からすべてのレコードを返します。

したがって、SomeColumn = 'test' の要素が 100 個あり、そのうち 50 個のレコードが、対応する ID の _element_brand テーブルに有効なレコードを持っていたことになります。それらの 50 のうち、具体的に brand_id = 1 を持っていたのは 20 だけでした...

最初の 2 つのサンプル クエリ (WHERE を使用した左結合と結合) は、具体的に 20 レコードを含む 20 レコードのみを返します。

LAST クエリは、'test' に基づいて限定された 100 件のレコードを返します。

これがあなたのデータシナリオに基づいているかどうかを明確にしてくれることを願っています...本や文書を見ても、それを理解しようとしている人が実際には明確にならない場合があります。

SELECT DISTINCT 
      STRAIGHT_JOIN
      e.id, 
      MATCH (e.heading) AGAINST ('+(room)') AS h_score, 
      MATCH (e.text) AGAINST ('+(room)') AS t_score, 
      ( SELECT SUM( MATCH (item.heading, item.text) AGAINST ('+(room)') ) 
           FROM _element_item
              JOIN item 
                 ON _element_item.item_id = item.id  
                AND MATCH (item.heading, item.text) AGAINST ('+(room)')
           WHERE 
              e.id = _element_item.item_id ) AS i_score 
   FROM 
      element AS e 
         JOIN _element_brand 
            ON e.id = _element_brand.element_id 
            AND _element_brand.brand_id = 1 

         JOIN _element_language 
            ON e.id = _element_language.element_id 
            AND _element_language.language_iso = 'en' 

         JOIN _element_region 
            ON e.id = _element_region.element_id 
           AND _element_region.region_id = 1 

         JOIN _element_type 
           ON e.id = _element_type.element_id 
          AND _element_type.type_id = 1 

         JOIN _element_group ON e.id = _element_group.element_id     
          AND _element_group.group_id = 1 
   WHERE 
          e.status = 1 
      and e.replacement_id IS NULL 
      AND MATCH (e.heading, e.text) AGAINST ('+(room)') 
   ORDER BY 
      t_score + h_score DESC 
   LIMIT 100

私は結合するように再構築しました。さらに、クエリを強制終了しているように見える i_score のフィールド select sum() をわずかに変更しました。また、上部にキーワード「STRAIGHT_JOIN」を追加して、提示された順序でクエリが実行されるようにしました。

フィールド選択に関する私の唯一のレビューの質問... あなたは参加しています

e.id から _element_item.item_id へ、次に _element_item.item_id から item.id へ....

そうは言っても、それは単純化されるかもしれません

e.id = item.id であり、それらが本当に同じである場合は _element_item テーブルを完全に削除できますが、特定の要素に対して多くのアイテムを持つ可能性があるブリッジ テーブルのように見えます。

于 2013-02-08T18:52:10.970 に答える