[Seasar-user:20279] Re: [DBFlute]OracleでDATE型カラムのインデックスが利用されない

しゃってん [E-MAIL ADDRESS DELETED]
2010年 10月 22日 (金) 16:42:10 JST


しゃってんです。

対応ありがとうございます。

現プロジェクトではアップデートができない状況のため、
最新版を参考にテンプレートの修正で対応する方向で検討することになると思います。



2010年10月22日15:42 kubo <[E-MAIL ADDRESS DELETED]>:
> 久保(jflute)です。
>
> しゃってんさん、ありがとうございます。
> もろもろ特にそちらとこちらで現象に違いはなさそうですね。
>
> とりあえず、DBFluteにて正式に対応しました。
> デフォルトは今まで通り、Timestamp にてバインド。
> littleAdjustmentMap.dfprop のオプションで
> oracle.sql.DATE を使った最適化を利用することができます。
> 詳しくは、ドキュメントをご覧下さい。
>
> // DBMSごとの取扱い - Oracleの日付型の最適化 | DBFlute
> http://dbflute.sandbox.seasar.org/ja/manual/reference/dbway/oracle/index.html#oracledate
>
> モジュール:DBFlute-0.9.7.5-SNAPSHOT
> ランタイム:DBFlute-0.9.7.5-04-SNAPSHOT
> にて反映されています。
>
> そもそもアップグレードできない状況であれば、
> DBFluteのソースを参考に、アプリ独自の ValueType を作って、
> DBFluteConfig経由でその ValueType を登録して下さい。
> アプリケーションの初期化時に DBFluteConfig の
> registerBasicValueType() で登録すればOKです。
>
> 以下を参考:
> o org.seasar.dbflute.s2dao.valuetype.plugin.OracleDateType
> o ...allcommon.DBFluteConfig のVelocityテンプレート
>
> とにかくアプリに oracle.sql.DATE を new してもらう、
> という感じですね。それ遺骸は、ランタイム内で全て解決。
>
> 2010/10/22 しゃってん <[E-MAIL ADDRESS DELETED]>:
>> しゃってんです。
>>
>>> 普通に更新で entity.setXxx(null) して更新してみて下さい。
>> こちらの環境で実行した場合もNullPointerException が発生しました。
>>
>> TnValueTypes.registerBasicValueType(keyType, new UtilDateAsTimestampType() {
>>       @Override
>>       public void bindValue(PreparedStatement ps, int index, Object
>> value) throws SQLException {
>>           if (value==null) {
>>               ps.setNull(index, java.sql.Types.TIMESTAMP);
>>           } else {
>>               ps.setObject(index, new
>> oracle.sql.DATE(DfTypeUtil.toTimestamp((java.util.Date) value)));
>>               //super.bindValue(ps, index, value);
>>           }
>>       }
>>    }); // switch
>>
>> とすることでNullPointerException は回避はできますね。
>>
>>
>> 2010年10月22日14:41 kubo <[E-MAIL ADDRESS DELETED]>:
>>> 久保(jflute)です。
>>>
>>>> ただその前に、もう一つお願いしたいです。
>>>> oracle.sql.DATEを有効にした状態で、バッチ更新を使って、
>>>> 該当のカラムを更新してみて下さい。
>>>> 実はこちらで試してて、oracle.sql.Datum クラス内で
>>>> NullPointerException が発生してしまいました。
>>> バッチ更新ってわけじゃなく、該当カラムを
>>> null で更新しようとすると発生するようです。
>>> 普通に更新で entity.setXxx(null) して更新してみて下さい。
>>>
>>> 2010/10/22 kubo <[E-MAIL ADDRESS DELETED]>:
>>>> 久保(jflute)です。
>>>>
>>>> しゃってんさん、色々と検証ありがとうございます。
>>>> 状況が随分はっきりしてきましたね。
>>>> (小林さんのフォローに感謝感謝です)
>>>>
>>>>> littleAdjustmentMap.dfprop あたりでのオプション扱いとして、
>>>>> 上記インナークラス部分を出力するような感じでもいいかもしれませんね。
>>>>
>>>> 勘がいいですねー。そういう感じのつもりです。
>>>> ただその前に、もう一つお願いしたいです。
>>>> oracle.sql.DATEを有効にした状態で、バッチ更新を使って、
>>>> 該当のカラムを更新してみて下さい。
>>>> 実はこちらで試してて、oracle.sql.Datum クラス内で
>>>> NullPointerException が発生してしまいました。
>>>> もしかしたら、検索条件のときだけ有効にするとか、
>>>> バッチ更新では除外するとか、何かしら処理を入れる
>>>> 必要があるのかもしれません。
>>>>
>>>> 2010/10/22 しゃってん <[E-MAIL ADDRESS DELETED]>:
>>>>>> ((OraclePreparedStatement) ps).setDATE(index, new DATE(date));
>>>>> #
>>>>> # org.seasar.extension.dbcp.impl.ConnectionPoolImpl を利用している場合、
>>>>> # Connection connection =
>>>>> ((ConnectionWrapperImpl)dataSource.getConnection()).getPhysicalConnection();
>>>>> # としないとClassCastExceptionとなるんですね。。。
>>>>> #
>>>>> で実行した場合、時刻まで考慮された検索結果が取得され
>>>>> INDEX RANGE SCAN で検索が実行されました。
>>>>>
>>>>>
>>>>> 同様に
>>>>>> TnValueTypes.registerBasicValueType(keyType, new UtilDateAsTimestampType() {
>>>>>>    @Override
>>>>>>    public void bindValue(PreparedStatement ps, int index, Object
>>>>>> value) throws SQLException {
>>>>>>        ps.setObject(index, new
>>>>>> DATE(DfTypeUtil.toTimestamp((java.util.Date) value)));
>>>>>>        //super.bindValue(ps, index, value);
>>>>>>    }
>>>>>> }); // switch
>>>>> #
>>>>> # SQLの組み立て時にFromToOption を利用すると時刻の指定ができなかったので
>>>>> # cb.query().setTargetDate_GreaterEqual(fromDate);
>>>>> # cb.query().setTargetDate_LessThan(toDate);
>>>>> # に変更しています。
>>>>> #
>>>>> の場合も時刻が考慮された検索結果が取得され、
>>>>> INDEX RANGE SCAN で検索が実行されました。
>>>>>
>>>>> littleAdjustmentMap.dfprop あたりでのオプション扱いとして、
>>>>> 上記インナークラス部分を出力するような感じでもいいかもしれませんね。
>>>>> ※あとFromToOptionで無変換で返すクラスがあればいいかなと。
>>>>>
>>>>>
>>>>> 2010年10月22日3:24 kubo <[E-MAIL ADDRESS DELETED]>:
>>>>>> 久保(jflute)です。
>>>>>>
>>>>>> しゃってんさん、まだDBFluteとしてどうするか考え中ですが、
>>>>>> DBFluteConfig にて、
>>>>>>
>>>>>> TnValueTypes.registerBasicValueType(keyType, valueType); // switch
>>>>>>
>>>>>>>>>>>>
>>>>>> TnValueTypes.registerBasicValueType(keyType, new UtilDateAsTimestampType() {
>>>>>>    @Override
>>>>>>    public void bindValue(PreparedStatement ps, int index, Object
>>>>>> value) throws SQLException {
>>>>>>        ps.setObject(index, new
>>>>>> DATE(DfTypeUtil.toTimestamp((java.util.Date) value)));
>>>>>>        //super.bindValue(ps, index, value);
>>>>>>    }
>>>>>> }); // switch
>>>>>>
>>>>>> に差し替えて試してみて下さい。
>>>>>> (「DATE」は、oracle.sql.DATE です)
>>>>>> 恐らく、java.sql.Date を指定したときと同じ実行結果に
>>>>>> なるんじゃないかと思われます。
>>>>>> こちらでも、30万件のテーブルを用意して比べてみると、
>>>>>> 安定してパフォーマンスが改善されます。
>>>>>> (30万件程度なのでわずかですが10msほど安定して差がでます)
>>>>>>
>>>>>> ※これをどう整理して提供するかがポイントですね...
>>>>>>
>>>>>> 2010/10/21 kubo <[E-MAIL ADDRESS DELETED]>:
>>>>>>> 久保(jflute)です。
>>>>>>>
>>>>>>>>> O/Rマッパには厳しい話ですね。。。
>>>>>>>>> いっそリフレクションでガツンってのは
>>>>>>>>> やはり無理矢理過ぎるかなぁ。
>>>>>>>>
>>>>>>>> リフレクションでガツンとは?
>>>>>>>
>>>>>>> コンパイルレベルでDBMSのJDBCに依存したくないので、
>>>>>>> リフレクションで oracle.sql.DATE を利用するように処理する
>>>>>>> って感じですね。(もちろん、Oracleの場合に限り)
>>>>>>>
>>>>>>> 自動生成ありきのツールなので、oracle.sql.DATE を利用する
>>>>>>> ValueType を自動生成するのが現実的かもと今考えています。
>>>>>>> (OracleのDATE型の場合はそのValueTypeを使う)
>>>>>>> アプリは基本的にOracleのJDBCに依存しても問題ないので。
>>>>>>> (一応、オプションで)
>>>>>>>
>>>>>>> 2010/10/21 Koichi Kobayashi <[E-MAIL ADDRESS DELETED]>:
>>>>>>>> 小林 (koichik) です.
>>>>>>>>
>>>>>>>> Date:    Thu, 21 Oct 2010 20:52:00 +0900
>>>>>>>> From:    kubo <[E-MAIL ADDRESS DELETED]>
>>>>>>>> To:      [E-MAIL ADDRESS DELETED]
>>>>>>>> Subject: [Seasar-user:20268] Re: [DBFlute]OracleでDATE型カラムのインデックスが利用されない
>>>>>>>>
>>>>>>>>> なるほど、そもそもDBMSに依存しないJDBCの型の中で、
>>>>>>>>> Oracle の DATE 型をぴったし当てはめられる型が存在しない
>>>>>>>>> というところですかね。
>>>>>>>>
>>>>>>>> そうですね.
>>>>>>>> JDBC および標準 SQL には日時 (日付と時刻) を
>>>>>>>> 扱うデータ型が基本的に TIMESTAMP 1 種類
>>>>>>>> (TZ 等は精度と同じ扱いとして) しかないのに対し,
>>>>>>>> Oracle には DATE と TIMESTAMP の 2 種類があり,
>>>>>>>> どちらも java.sql.Timestamp にマッピングするのが
>>>>>>>> 問題の根本でしょうね.
>>>>>>>> 歴史的なものなのでしょうがないですけど.
>>>>>>>>
>>>>>>>>> DATE型カラムのメタデータが:
>>>>>>>>>   ojdbc5.jar = java.sql.Types.DATE
>>>>>>>>>   ojdbc6.jar = java.sql.Types.TIMESTAMP
>>>>>>>>> となっていたので TIMESTAMP の指定で問題ないかなと
>>>>>>>>> 思ったのですが、(実際検索の動きとしては問題ないですが)
>>>>>>>>> 内部的には型違いと。
>>>>>>>>
>>>>>>>> Oracle の DATE が java.sql.Types.DATE なのは
>>>>>>>> 単純に間違ってますよね.
>>>>>>>> Oracle の DATE は日付型ではなく日時型なので.
>>>>>>>> ただし,Oracle の日時型には 2 種類ある...
>>>>>>>>
>>>>>>>>> > Oracle JDBC ドライバには oracle.sql.DATE という
>>>>>>>>> > 型があるので、java.sql.Timestamp からこの型に
>>>>>>>>> > 変換して、OraclePreparedStatement#setDATE() に
>>>>>>>>> > 渡すなんてのが Oracle 的に好ましいやり方なのかも。
>>>>>>>>>
>>>>>>>>> O/Rマッパには厳しい話ですね。。。
>>>>>>>>> いっそリフレクションでガツンってのは
>>>>>>>>> やはり無理矢理過ぎるかなぁ。
>>>>>>>>
>>>>>>>> リフレクションでガツンとは?
>>>>>>>>
>>>>>>>>
>>>>>>>> S2JDBC でも同じ問題は起こり得るので
>>>>>>>> 何か考えた方がいいかなぁ.
>>>>>>>> 幸い (?),S2JDBC では
>>>>>>>>
>>>>>>>> @Temporal(TemporalType.TIMESTAMP)
>>>>>>>> public java.util.Date xxx;
>>>>>>>>
>>>>>>>> public java.sql.Timestamp xxx;
>>>>>>>>
>>>>>>>> という 2 種類の書き方ができるので,前者の場合は
>>>>>>>> DATE,後者の場合は TIMESTAMP にマップして,
>>>>>>>> 前者は OracleDialect で oracle.sql.DATE に
>>>>>>>> 変換するとか.
>>>>>>>> S2JDBC-Gen と辻褄合うのかなぁ...
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> <component name="koichik">
>>>>>>>>    <property name="fullName">"Koichi Kobayashi"</property>
>>>>>>>>    <property name="email">"[E-MAIL ADDRESS DELETED]"</property>
>>>>>>>>    <property name="blog">"http://d.hatena.ne.jp/koichik"</property>
>>>>>>>>    <property name="twitter">"http://twitter.com/koichik"</property>
>>>>>>>> </component>
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> Seasar-user mailing list
>>>>>>>> [E-MAIL ADDRESS DELETED]
>>>>>>>> https://ml.seasar.org/mailman/listinfo/seasar-user
>>>>>>>>
>>>>>>>
>>>>>> _______________________________________________
>>>>>> Seasar-user mailing list
>>>>>> [E-MAIL ADDRESS DELETED]
>>>>>> https://ml.seasar.org/mailman/listinfo/seasar-user
>>>>>>
>>>>> _______________________________________________
>>>>> Seasar-user mailing list
>>>>> [E-MAIL ADDRESS DELETED]
>>>>> https://ml.seasar.org/mailman/listinfo/seasar-user
>>>>>
>>>>
>>> _______________________________________________
>>> Seasar-user mailing list
>>> [E-MAIL ADDRESS DELETED]
>>> https://ml.seasar.org/mailman/listinfo/seasar-user
>>>
>> _______________________________________________
>> Seasar-user mailing list
>> [E-MAIL ADDRESS DELETED]
>> https://ml.seasar.org/mailman/listinfo/seasar-user
>>
> _______________________________________________
> Seasar-user mailing list
> [E-MAIL ADDRESS DELETED]
> https://ml.seasar.org/mailman/listinfo/seasar-user
>


Seasar-user メーリングリストの案内