- - PR -
10万件のデータでmin()関数を使ったときに実行されない
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2009-03-04 18:25
横から少し失礼。
SQLiteの独自仕様は、MySQLの独自仕様と似た部分があります。 MySQLでは、 「group byでグループ化することで一意になるなら、group byに指定していない列も指定可能。ただし、エラーにしないけど、一意にならないなら結果は保証しない」 という、誤りを生む仕様となっています。(MySQL 5.0以降は、この仕様を無効化するオプションあり) http://dev.mysql.com/doc/refman/4.1/ja/group-by-hidden-fields.html?ff=nopfpls 私自身は、SQLiteでこの部分を明確にしたドキュメントは見つけていませんが、同じようになっているのかも。 | ||||||||||||
|
投稿日時: 2009-03-04 18:28
↓ 「selectで」が抜けていました。
| ||||||||||||
|
投稿日時: 2009-03-04 19:06
とりあえず「100件ある」ことは「最小値のroom.idがとれてる」ことにはなりません。
外部キーは設定してませんが
と、なりました。 # あくまでうちのsqliteでは、ですけど。 忠犬さんが示してくれていますが、 MySQLと同じように「group byで一意になるなら」自動で選択してくれる機能であるとすれば、 今回はそのケースにはあてはまらないですよね。 (group by property_idとgroup by room.id, property_idとでは結果が違う) # なんでとまっちゃうかというのにも関係してる・・・とは断言できないのですが^^; [ メッセージ編集済み 編集者: デューン 編集日時 2009-03-04 19:12 ] | ||||||||||||
|
投稿日時: 2009-03-04 20:16
>忠犬様
やはり「誤った」仕様だったんですね(汗。これは修正するしかなさそうですね… >デューン様 げげ、大変な結果になってますね(汗。 このSQLを作るまでに結構かかったんですが、動かない(or誤った)SQLなら修正しなければなりませんね(汗。 僕の持てる知識総動員で出した答えが「誤り」だったのは悲しいですが、他の方法を模索します。よろしければヒントをいただけないでしょうか? (新しいSQLを組み立てた後「動かない」の現象が治っていることを祈って取り合えず新しいSQLの組み立てにシフトします。治らなかったら・・・汗) _________________ 有末 清華 crazy(){for;;{you();}} - プログラマの覚書 | ||||||||||||
|
投稿日時: 2009-03-04 22:44
内側のselectの、今話題になっているroom.idって、どこにも使っていないんじゃないですか?
room.idは外してしまってもいいような気がします。 で。結果が戻ってこない理由ですが、予測では、 room_cost.house_rent = anon_1.minprice のところが、どちらもインデックス無しになってるからではないかと。 anon_1の件数が1万件、room_costが10万件なので、最悪の状況だと10万×1万=10億の 比較が発生します。 その前のproperty_idの比較で絞り込めているといいんですが。 とりあえず、room_cost.house_rentにインデックスを張ってみては? あと、こういう使い方をするのであれば、roomテーブルとroom_costテーブルは 一つに纏めてしまった方が良さそうな気がします。 一部屋に複数の値段がつく可能性があるなら分けるべきですけど。 戻ってくる結果の数は、必ずしもpropertyテーブルの件数とイコールにはなりませんよね? 複数の部屋が同じ値段である場合は、複数の結果が戻ってくる筈です。 他に気になる点としては、内側のselectにorder byしているところ。 JOINの時に高速化に効くならいいのですけど、そうでなければソートするだけ無駄なので、外してしまってもいいのではないかと。 | ||||||||||||
|
投稿日時: 2009-03-05 00:22
自分も最初はそう思ってた(property_idと価格の最少が拾えればいいのかと思っていた)んですが、 組んでいるSQLを見ていると取得したいのは 「property毎の最小の価格を持つroom.id」が欲しいような気がしています。 列は省略されているのでどのテーブルにどの情報が入っているのかはわからないままですが。 room.idから価格は再取得できますが、価格からもproperty_idからもroom.idは再取得できないからっていうのがそう感じた一番の理由なんですけどね。 ヒントですか。 もっといい手があるかもしれませんが、自分が今思いつくのでは、自己結合でしょうか。 (コスト的にどうかは考えてません) select room_id,house_rent,(select count(house_rent) from room_cost B where B.house_rent < A.house_rent ) from room_cost A とすると、room_costテーブルのランク付けができます。 select room_id,house_rent,(select count(house_rent) from room_cost B where B.house_rent < A.house_rent and B.room_id = A.room_id ) from room_cost A とすると、room_idごとのランク付けができます。 (もちろん、room_idは重複しませんから意味ないですけど、ヒントですので。) | ||||||||||||
|
投稿日時: 2009-03-05 01:50
>すなめり様
room_cost.house_rentにインデックスを振ってみても結果は変わりませんでした(Core 2 Duo 3GHzだからCPUのせいにはできないですね涙)
かなり初期のころ Cost の内容をオブジェクト思考で考えてまとめていたんです。その構造が今にも引き継がれていて…
実際の処理ではやっていません。実験的に見やすくするように書いた奴を組み合わせたりしているうちにここにもそれをそのまま書いてしまっただけなんです >デューン様
まさにその通りです。欲しいのは「各物件内の最安」の部屋情報なので ランク付けという作業は始めて聞きました。行っている処理はSQL文からはよくわからないのですが、実行結果から推測するに「house_rentで並び替えて同じ値段の物の順位は一緒にして順位をつけた」ということで間違いないでしょうか?加えて、これをどう利用したら行いたい処理が実行できるのか分かりません……下記のようなSQLをくんで見ましたが遅いしよく分からないってのが正直なところです(汗。 select id, property_id, house_rent, (select count(house_rent) from ( select room.id as id, property_id, room_cost.house_rent as house_rent from room join property on room.property_id = property.id join room_cost on room_id = room_cost.room_id ) as B where B.house_rent < A.house_rent and B.property_id = A.property_id) from ( select room.id as id, property_id, room_cost.house_rent as house_rent from room join property on room.property_id = property.id join room_cost on room.id = room_cost.room_id ) as A たぶん根本的に理解していない… [ メッセージ編集済み 編集者: 有末 清華 編集日時 2009-03-05 01:51 ] [ メッセージ編集済み 編集者: 有末 清華 編集日時 2009-03-05 01:51 ] [ メッセージ編集済み 編集者: 有末 清華 編集日時 2009-03-05 01:52 ] | ||||||||||||
|
投稿日時: 2009-03-05 11:41
select room_id,house_rent,(select count(house_rent) from room_cost B where B.house_rent < A.house_rent ) from room_cost A という書き方は、SQLiteでは許してくれないようでした すいません、ヒントじゃなくなってしまうんですが、
というのはどうでしょうか。 提示してもらったSQLですが、 propertyは必ずしもjoinする必要はないのかなと思います。 (roomテーブルにあって、propertyテーブルにないproperty.idを削れますが、このあとのタイミングでもよいのではないかと思います。) |