Seo tools

Neo Inspiration

  • Search

    • About Me

      • inspi 改め
        jakk@webアーキテクト(自称)
        php,javascript,seoなど
        得意技は extract();



  • Categories

  • Ranking

  • Comments

  • Others


  • cakePHP で GROUP BY の壮絶バッドノウハウ

    いろいろなところで紹介されているように
    普通に $condition の中にぶちこめばいけるんですが、
    こんなかんじ

    $this->モデル->findAll(
            $conditions = “GROUP BY title”,
            $limit = “”
    );

    例えばINとか、LIKEとか使ってごりごりやっていくときって
    Array で $condition つっこむのでそれのやり方のお話

    普通にやると

    $this->モデル->findAll(
            $conditions = array(’Table.uid’ => Array , ‘GROUP BY Table.title’),
            $limit = “”
    );

    こんなかんじで、Arrayの一つとして GROUP BY を渡せばいいと思うんですが、
    これじゃうまくいきません。
    なぜなら Array の要素はすべて AND でつなげてしまうから。

    つまりこれをSQLにすると

    WHERE Table.uid=1 AND GROUP BY Table.title

    なんていうSQLを投げてしまうわけです。
    もちろんエラーに。

    で これをどう解決するかというと
    こういう風にできます


    $this->モデル->findAll(
            $conditions = array(’Table.uid’ => Array , ‘Table.a<>”" GROUP BY Table.title’),
            $limit = “”
    );

    *2008/03/03追記
    コメントをいただいたので修正してみました。

    $this->モデル->findAll(
            $conditions = array(’Table.uid’ => Array , ‘1=1 GROUP BY Table.title’),
            $limit = “”
    );

    わかるかな。。。
    *Table.a<>”" という条件はほしいデータの抽出にまったく影響しないダミー条件です(なんでもいいんだけど)

    *2008/03/03追記
    自前の1100万件のレコードのあるテーブルで上の二つをExplainしてみると
    table type possible_keys key key_len ref rows Extra
    Table_Name ALL NULL NULL NULL NULL 11006100 Using where
    Table_Name ALL NULL NULL NULL NULL 11006108
    となります。

    ようは Table.a<>“” というのはWHERE句として解析して
    その後で出力するんですが、
    WHERE 1=1 はWHERE句の処理をせずに、無視してSQLを解析するので、
    早くなります。
    従って処理速度は table.a<>“” を使った時より圧倒的に早くなります。

    ちなみに WHERE 1 でもOKだったので文字数を減らすならこうなります。

    *2008/03/03追記
    $this->モデル->findAll(
            $conditions = array(’Table.uid’ => Array , ‘1 GROUP BY Table.title’),
            $limit = “”
    );

    Table.a<>”" をGROUP BY に書き加えただけなんですが、
    これでうまくいきます。
    ようは

    WHERE Table.uid=1 AND Table.a<>”" GROUP BY Table.title

    というSQLの正しい構文にするためにダミーの条件を GROUP BY が入ってるArrayのとこに書き加えてあるんです。
    なんという力技。。。

    ダミー条件とはいえ若干だろうけど負荷も大きくなるし、
    もちろん激しく無駄w

    そのままSQLかけという話もありますが
    こういう方法もありますということで。


    4 Responses to “cakePHP で GROUP BY の壮絶バッドノウハウ”

    1. ku Says:

      cake/libs/model/datasources/dbo_source.php を見て絶望的な気分になっていたところでこのエントリを発見して救われました。ありがとうございます!

    2. Jakk Says:

      リファラがTwitterのアドレスになってて
      あれ?っておもったのですw

      ついでにAddしちゃいました><

    3. a Says:

      Table.a”"なんて書くと、パフォーマンスに影響が出そうですね。

      1.2betaのdbo_source.test.php には以下のようなテストがありました。
      たぶん同じことをしているのでしょうが、こちらならDBMSの最適化機能で
      条件無視されそうなんでこっちのほうがよさそうです。

      $conditions = array(
      ‘Thread.project_id’ => 5,
      ‘Thread.buyer_id’ => 14,
      ‘1=1 GROUP BY Thread.project_id’
      );
      $result = $this->db->conditions($conditions);

    4. Jakk Says:

      コメントありがとうございます。

      1=1

      確かにこのほうが無駄な内部SQL投げないとおもうので
      よさそうですね。

      いただいた情報を元にエントリを修正しました。
      情報ありがとうございました!

    Leave a Reply

    2008/11/22 05:07:34