2008年12月11日

[mysql 14707] Re: UNIONしたテーブルとJOINする際にインデックスが使われずテーブルスキャンになるのを回避する方法をご存じの方はご教示いただけますと幸いです。


「はてな」への質問は、約1年前のようですが、MySQLは4.1.22のままなのでしょうか?

検証するために、具体的なデータ例(ヒットすべきデータ、ヒットすべきでないデータ)を
提示できませんか?

無条件の検索結果をUNIONで繋ぐなら、テーブルスキャンされて当然だと思います。
また、日時などの演算を検索条件に含めた段階で、MySQLではインデクスでの絞り込みが

できないと思います。

まだ具体的に考えた訳ではないですが、「直近の1件」というのを、「ORDER BYとLIMITを
組み合わせる」、「NOT EXISTSなどで取り出す」といった方法になるように感じます。


> Date: Thu, 11 Dec 2008 19:49:28 +0900
> From: hiroki.tamakoshi@xxxxx
> Subject: [mysql 14706] UNIONしたテーブルとJOINする際にインデックスが使われずテーブルスキャンになるのを回避する方法をご存じの方はご教示いただけますと幸いです。
> To: ml@xxxxx
>
> こんにちは。
> 株式会社ビービットの玉越です。
>
> UNIONで悩んでいます。
> たぶん解決不能と思うのですが、解決不能なのかどうかご存じの方はご教示いただけますと幸いです。
> 長文で失礼致します。
>
> ■前提
> 構造の異なるテーブルtableA, tableBがあります。
> これらとtableCをJOINする必要があります。
> インデックスは適切に張っています。
>
> tableA
> id
> C_id
> time
> description
>
> tableB
> id
> C_id
> time
> (←descriptionがない)
>
> tableC
> id
> time
>
> ■問題例1
>
> SELECT
> union_table.description
> FROM
> ( SELECT
> tableA.C_id,
> tableA.description
> FROM
> tableA
> UNION ALL
> SELECT
> tableB.C_id,
> NULL
> FROM
> tableB
> ) AS union_table,
> tableC
> WHERE
> union_table.C_id = tableC.id
>
> union_table.C_idは、tableA.C_idかtableB.C_idのどちらかです。
> なので、インデックスを効果的に使ってくれると期待します。
> ところが、この方法ではtableA, tableBをテーブルスキャンするようです。
>
> ( .. UNION ALL .. )をすると、その中までは見てくれなくなるようです。
>
> http://q.hatena.ne.jp/1198431011にも同様のことがあります。
>
> ■解決案1
>
> 上記にある通り、下記のようにすればよいようです(これから実験します)
>
> SELECT
> tableA.time
> FROM
> tableA,
> tableC
> WHERE
> tableA.C_id = tableC.id
> UNION ALL
> SELECT
> tableB.time
> FROM
> tableB,
> tableC
> WHERE
> tableB.C_id = tableC.id
>
> 一度まとめテーブルを作るのではなく、結果をそれぞれ作ってからまとめる、
> という方法です。
>
> ■解きたい問題
>
> 上記だけであれば問題は解決するのですが、私が行いたいのは下記です。
>
> SELECT
> union_table.description
> FROM
> ( SELECT
> tableA.C_id,
> tableA.time,
> tableA.description
> FROM
> tableA
> UNION ALL
> SELECT
> tableB.C_id,
> tableB.time,
> NULL
> FROM
> tableB
> ) AS union_table,
> tableC
> WHERE
> union_table.C_id = tableC.id
> AND tableC.time - union_table.time = (
> SELECT
> MIN( tableC2.time - union_table2.time )
> FROM
> ( SELECT
> tableA.C_id,
> tableA.time,
> FROM
> tableA
> UNION ALL
> SELECT
> tableB.C_id,
> tableB.time,
> FROM
> tableB
> ) AS union_table2,
> tableC AS tableC2
> WHERE
> union_table2.C_id = tableC.id
> AND tableC2.id = tableC.id
>
> tableC.timeから見て、tableAとtableBのtimeのうち、一番近いものを一つだけ持ってくる
> という操作です。
>
> これを解決案1のようにしてしまうと、別々に持ってきたものをUNION ALLするので、
> 一つだけではなく二つ持ってきてしまうことになります。
>
> 解決は無理そうと思っていますが、もし可能だよ、という情報をご存じの方がいらっしゃいましたらご教示いただけますと幸いです。
> また、不可能だよ、という情報ももしいただけますと、これ以上悩まなくて済むので同様にありがたいです。
>
> よろしくお願い致します。
>
>
> --
> -------------------------------------------------------
> ◆ビービットはチームマイナス6%に参画しています◆
> -------------------------------------------------------
> 株式会社ビービット 玉越 大輝
> ユーザビリティ コンサルタント
> beBit,Inc. Tamakoshi Hiroki hiroki.tamakoshi@xxxxx
> --------------------------------------------------------
>
> ◆◆9月29日(月)より下記に移転いたしました◆◆
>
> 〒102-0071 東京都千代田区富士見2-14-37 FUJIMI EAST 1F
> TEL: 03-5210-3891 / FAX: 03-5210-3895
> URL: http://www.bebit.co.jp/
> --------------------------------------------------------
> ◆◆◆お知らせ◆◆◆
> ・ユーザビリティ実践メモ(毎週月曜日更新)
> http://www.bebit.co.jp/memo/
>
> ・ビービット書籍 『ユーザ中心ウェブサイト戦略』発売中
> http://www.amazon.co.jp/gp/product/4797333529/
>
_________________________________________________________________
「ブリーフケースからお引越し」無料25GBのファイル保存サービス
http://go.windowslive.jp/share/skydrive.html


投稿者 xml-rpc : 2008年12月11日 20:19
役に立ちました?:
過去のフィードバック 平均:(0) 総合:(0) 投票回数:(0)
本記事へのTrackback: http://hoop.euqset.org/blog/mt-tb2006.cgi/79963
トラックバック
コメント
コメントする




画像の中に見える文字を入力してください。