IT

【ORACLE】サブパーティションプルーニングのバグ


有識者との問い合わせのやり取りの中で発覚した、結論からいうとOracleのバグらしいのだが、
俺自身がよくわかっていないので情報整理する意味で書いてみる。
内容としては、厄介なことに同じSQLでも結果が異なるケースをもたらすようだ。


 


ストレイテナーと確率3(本当にCLONEは「よく耳にする」わけではないのか?)




前回の続き。

前回は「60分以内にどの曲が選ばれやすいか?」というのをシミュレーションした。
1.シングル・アルバムで重複している曲程選ばれやすい
2.演奏時間が短い曲程選ばれやすい
以上の2点が「選ばれやすさ」-選択頻度-を上げる要因になっていることがわかった。
結果的に、1.の点において4つの重複を持つ「SIX DAY WONDER」が堂々の1位となった。

なったわけだが、その後も何度かシャッフル再生し続けていたらやっぱりどうもCLONEを耳にする頻度が高い気がしてならない。
前回の検証においてはCLONEは重複点と演奏時間の関係上、選ばれやすさでいえば11位だったが、
この前なんか10曲目CLONE(CREATURES)⇒11曲目(忘れた)⇒12曲目CLONE(ベスト)という並びになったのだ。
本当にCLONEの選ばれやすさが11位なら、相当レアな確率を引き当てていることになる。
というわけで今回は視点を変え、「CLONE」という曲に着目して、
”本当にCLONEは選ばれやすいわけではないのか?”というのを考えてみたいと思う。


 


【ORACLE】RANK関数


OracleのRANK関数-いわゆる「順位」をつけるための関数-の使い方の個人的なメモ


基本的な使い方はSELECTの項目内に以下のように記述する↓

rank() over(order by COLUMN_NAME [ASC|DESC] )  

という感じ。
・何か指定できるみたいだが、この使い方だと同値は同順になり、次の値から重複した分を加味した順位になっていく。
・検索結果は、over()内に指定した順序で並び替えられるので、通常順序付けにあたって最後部につけるORDER BYは不要。



 


【java】Listについて


勘違いしていたというか、内心ちょびっとだけ「そんなにうまくはいかないか」と思っていたら実際そうだったんだが、
java.util.Listは=で同じ型の別変数に移しても内容が維持されるらしい。
2つの異なる変数間で同じメモリの内容を共有するようになるというか。

例えば、List(変数名:list)で5つの要素を格納した後、
別のList(変数名:list2)にlistをそのまま移して、
list2側でremoveかけると、list2もlistも要素数が4になる(list2だけ5⇒4に減るわけではない)。


 


【java】時間の加算とオフセットの扱い


javaで時間を加算する実装例。
ストレイテナーのシミュレーションするときにテスト的にやったのでメモとして残す。

特に「時」(Hour)の部分がない文字列からDateFormatを通して時間に変換した後、別の時間と合計する場合は、
オフセットを適切な箇所に加算ないし減算してあげる必要がある。
これは、「時」の部分がない文字列のDateFormat#parseでは1970/01/01 00:00:00をもとに変換されたDateインスタンスを得るからである。
よって、基準となる1970/01/01 09:00:00からすると過去の日時であるため「負数」となり、
これを単純加算していくと負数+負数でどんどん小さくなり、結果的にわけのわからん時刻になる。

例えば47分2秒+14分58秒だが、当然だが「1時間2分0秒」という値がほしいのに対し、
オフセット加算をしないと「16時間2分」になる。
これは、
47分 2秒=1970/01/01 00:47:02=-29578000ミリ秒
14分58秒=1970/01/01 00:14:58=-31502000ミリ秒
で、合計すると-61080000ミリ秒となり、
1970/01/01 09:00:00からすると「過去の日時」を指すことになるので、
結果的に「1969/12/31 16:02:00」になる。
これをHH:mm:ssでパースして「16:02:00」、つまり「16時間2分」になってるように見えてしまうのだ。



 


ストレイテナーと確率2


前回の続き(?)で再び「iPhoneシャッフルでストレイテナーを再生」するときの考察をしてみる。
今回は「60分という制限時間内でどのアルバム・曲が一番聴かれる可能性が高いのか?」という点に着目してみたい。
この「60分」という制限時間は前回書いた通り俺の会社への出勤(または帰宅)にかかるDoorToDoorの時間とほぼイコールである。
要するに「1回の出勤においてシャッフルで曲を聴いた場合一番よく聴いているのはどのアルバム・曲か?」というのを調べる。

これは普段何気なく聴いているだけだと実際のところあまり気に留めていないが、
巨視的な視点で見たときには数学における確率の諸法則に従っているはずである。
ここでは、シャッフル再生が完全ランダムな曲順を保証するという前提で、
乱数によりシミュレーションを行うプログラムを作成し、いわゆるモンテカルロ法で結果を評価する。

※ちなみに最新アルバム「Behind The scene」は検証の対象に入っていません


 


ストレイテナーと確率(iPhoneシャッフルとはぐれメタルを仲間にする確率との対比考察)


通勤や帰宅時、または一人での外出時では、
基本的にiPhoneのシャッフル機能を使ってストレイテナーをアーティスト選択して再生している。
シャッフル再生というのが、”完全にランダムに曲順を決めている”という前提だと、
極稀に「おお…この曲が連続して流れるのって結構レアなんじゃあねーかッ!」と思う組み合わせに遭遇することがある。
ただいつもは数値的にそのレア度を評価したわけではないので、その時は「なんとなくレアかも」くらいにしか感じていない。
ちなみに今日なんかはSILLY PARADE(インスト)⇒SILLY PARADE(シングル)が連続して流れた。
気になったので確率を計算してみたらかなり天文学的確率だった。


 


【ORACLE】FOR UPDATEの勘違いと真実(今さら)、あと実験


Oracleの「FOR UPDATE OF TABLE.COLUMN」は、指定した項目を基準としてレコードの排他をかける構文だと思ってたが、

SELECTの対象が複数存在する場合にどのテーブルをロックするかを指定するもとの情報らしくて、

SELECT対象が1テーブルだけだとあまり意味がないらしい。

また、仮に複数あったとしても、「そのテーブルを(ロックする)」という意味しか持たず、

項目を指定することによる、その項目に関連する排他の意味合いはないようだ。(じゃあ書かせんなよ…FOR UPDATE OF TABLEだけ(COLUMN書く必要ない)でいいやんけ)

要するに項目Aと項目Bがあったら「FOR UPDATE OF 項目A」でも「FOR UPDATE OF 項目B」でも効果は同じ、ということらしい。



なお、前提として、ここでいう「そのテーブルを」というのは、FOR UPDATEを付けているSELECT側の条件(WHERE句等)に左右される。

つまり「テーブル全体をロックする」という意味ではなくて指定された条件に該当するレコードのみがロックされる。



まあでも確かに冷静に考えると、

指定した項目によっては「(その項目を指定したからって)だから何?」っていう気になるのもわかる。

これは、自身のプロジェクトにおいて、「FOR UPDATE OF TABLE.COLUMN」の「COLUMN」に指定される項目が、

得てしてKEY項目であることが多いことに由来するのだろう。

つまり「そのKEYのレコード全体をロックする」という意味合いとして使っている(書いている)と、

結果的には勝手に”勘違いしていた”ことになるのだが、

そもそも、もともとFOR UPDATE OF TABLE.COLUMNの".COLUMN"には、

Oracle的には、項目自体に対する排他等の意味や目的はなくて、

「そのテーブルを」の判断基準にしか使ってないんだから、

指定されたからといって、例えばフラグ的意味合いの項目だったとすると”値が1のレコードだけロックするの?”とか、

様々疑問が出てくることは確かである。

それに、KEY以外の項目を指定したとしたら(あるいはKEYなしテーブルだったとしたら)、

排他ができない無意味な構文になるかというと、それはそれで本末転倒であるし、

そういうことも考えると「よく考えればわかるだろ」と言われるとそうでもある。



結合してデータを取得する際に同じ名前の項目が一度のSELECT内で複数存在する場合に、

「どのテーブルの」項目かを区別する指定を明記しないと実行できずに怒られる仕様がある。

このFOR UPDATEの項目指定もそれとよく似ていて、その理由というか、経緯も多分同じなんだろう。

「Aテーブル.項目B」と「Cテーブル.項目B」が存在するとき、

単に「FOR UPDATE OF 項目B」とだけ書いても「どっちのだよ?」という気になるから、テーブル名から書かせるようになっている…

そんなところなんだろう。

だから「テーブルどころか項目名まで書かせている」というよりは「項目を書かせるためにテーブルまで指定させている」というほうが正しい気がする。

でも項目を書くことの意味がない(指定する項目によって排他の効果は変わらない)なら出発点がまず間違っていると思うのだ。

(これは俺の予想に過ぎないから事実がどうかは知らない…)