読書会(Javaパフォーマンス)第7回議事録

[ 戻る ]


============================================================
Java読書会BOF 「Javaパフォーマンス」を読む会 第7回
============================================================
.. csv-table:: 開催概要

   "日時","2015年12月26日 10:00 - 17:00"
   "場所","川崎市教育文化会館 第3会議室"
   "出席者(敬称略)","高橋(徹)、高橋(智)、根本、平山、後藤、中澤、小棚木、松永、今井、遠藤、伊藤、吉本、藤井、石黒、岩室(書記)"

11章 データベースのベストプラクティス
============================================================

11.1 JDBC
------------------------------------------------------------

11.1.3 JDBCのコネクションプール
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

11.1.4 トランザクション
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* トランザクションのセマンティクスは4種類ある。⇒ 11.1.4.2参照
* RDB毎に選択可能なセマンティクスが異なる。
    * DB2など4種類全てがサポートされているRDBもある。
* 最近はMySQLよりPostgreSQLを推奨する傾向が出てきている模様。
    * GitLabやRedmineなど。

11.1.4.1 JDBCでのトランザクション制御
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* p.347 サンプルコード3行目末尾の「{」は「;」の間違い。
* 「addBatch()の存在を初めて知った」⇒実は昔からある。
    * ORマッパではどのように取り扱えばよいか?
    * 限界や制限は? (システム的な制約はないために)プログラマが対処する必要あり?
* サンプルコードのように20万件程度をオンメモリで処理でしも問題にならないことに感心。
    * とは言え、オンプレミス環境なら問題にならなくても、最近のクラウド環境だと逆に1VMあたりのメモリ容量が限られている可能性はある。
* p.349 表11-1の下の段落: 「1行目と4行目」は「2行目と4行目」の間違いか?
    * → どちらも自動コミットモードでトランザクション制御は行っていないので正しい。

11.1.4.2 トランザクションの分離とロック
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* トランザクションのセマンティクスは、結局READ_COMMITTEDに集約されているのではないか?
    * それ以外使ったことがない人も。
* REPEATABLE_READが必要なのは金融系?
* 表示したデータを別のページで更新するような場合は、標準のトランザクション機能だけでは対応できない。
    * 通常は楽観的ロックで実装する。(これで問題がないかを確信できない人も)
* TRANSACTION_NONEはどういうときに使う? ⇒ 以下のようなケースで使われるのではないか?
    * 読み取り専用 (前もって作っておく)
    * メンテナンス中で矛盾が発生してもよい状況でのデータ更新
* 例外としてOptimisticLockExceptionが存在するということは、JPAでは標準の機能として楽観的ロックを提供している?

11.1.5 リザルトセットの処理
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* リザルトセットを「戻れる」設定にすると、過去の結果をメモリ上に保存するので、メモリが足りなくなる場合がある。
    * デフォルトで「戻れる」設定になっているJDBCがあったはずだが、どれだか思い出せない。

11.1.5.1 その他の取得行数の指定方法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

11.2 JPA
------------------------------------------------------------

11.2.1 トランザクションの処理
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* p.358 StockOptionPriceImpl はここで直接使用してよいのか?
    * コードの全貌がわからないので何とも言えない。
* JTAはJavaEE限定か? → yes
* JavaSEではJPAの機能を使ってトランザクションを制御する必要がある。
* JavaSEでJTAを使おうとする場合は、単にJTAの参照実装を用意するだけではだめで、必要なミドルウェアや実装を準備する必要がある。
* 分散トランザクションはどのようなケースで必要?
    * 複数のDBやサブシステム間でトランザクションを必要とするケースで必要。
        * 銀行間の取引(例えば振り込み処理など)だと、双方のトランザクションが一貫している必要がある。
* Webアプリケーションでも、例えばECサイトでのカード決済やポイント処理を行う場合は、ローカルのDB更新と外部連携のトランザクションが一貫していなくてはならない。

11.2.2 JPAでの出力の最適化
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* マイクロベンチマークの結果では、バッチ処理を積極的に行った方がパフォーマンスが上がるように見える。
    * とは言え、実績や経験がないとどのようなトラブルが発生するのかはわからない。
    * トラブル要因を調査する妨げになる場合も考えられる。(1回のDB操作で行われる処理量が増大して、調査範囲の絞り込みが困難になるなど)

11.2.3 JPAでの入力の最適化
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

11.2.3.1 データの読み込み量を減らす
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

* LAZYの特性を考慮して使わないとトラブルの要因になりやすい。
    * 特にone-to-manyの関係があると、1画面表示するだけで数千のクエリが流れる場合がある。
* O/RマッパによってオブジェクトとDBのレコードが直接紐付いていることを認識しないと、想定外の更新クエリが流れる場合がある。
    * Stringがnullになっているカラムを空文字列に置き換える処理を行ったために大量のUPDATEが実行されるなど。
* オブジェクト操作とDBアクセスとのギャップが認識されないためにトラブルが生じやすい。
    * 明示的に、検索結果を入れ物となるオブジェクトに詰め込んだり、指定したオブジェクトをDBに書き込んだりする機能だけが提供されている方がよいのではないか?

11.2.3.2 クエリでのJOINの使用
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

11.2.3.3 バッチ化とクエリ
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

11.2.4 JPAのキャッシュ
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

11.2.4.1 デフォルトのキャッシュ(遅延読み込み)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

11.2.4.2 キャッシュと事前取得
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

11.2.4.3 JOINを使った取得とキャッシュ
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

11.2.4.4 クエリの回避
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

11.2.5 JPAのキャッシュのサイズ指定
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

11.2.6 JPAの読み取り専用エンティティ
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* キャッシュの更新はどのようにおこなわれるべきか?
* DBが更新されてもキャッシュが更新されないときはどのようにすればよいか?
* 暗黙のキャッシュなど無い方がよいのでは。

11.3 まとめ
------------------------------------------------------------

12章 Java SEのAPIのパフォーマンス
============================================================

12.1 バッファー付き入出力
------------------------------------------------------------

12.2 クラスのロード
------------------------------------------------------------

12.3 乱数の生成
------------------------------------------------------------

* SecureRandomは/dev/randomを使っているのか?
    * 使っている実装は存在する。「securerandom.source=/dev/urandom」のような設定も可能。
    * Java8ではデフォルトでは使われない? いろいろな設定が可能らしい。

12.4 JNI
------------------------------------------------------------

12.5 例外処理
------------------------------------------------------------

* nullチェックせずNullPointerExceptionをキャッチする方法でもいいのではないか?
    * とは言え気持ち悪さは拭えない気がする。

12.6 Stringのパフォーマンス
------------------------------------------------------------

12.7 ログの記録
------------------------------------------------------------

12.8 コレクションAPI
------------------------------------------------------------

12.8.1 synchronizedか否か
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

12.8.2 コレクションのサイズ指定
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

12.8.3 コレクションとメモリの効率
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

12.9 AggressiveOpts
------------------------------------------------------------

12.9.1 代替のクラス実装
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

12.9.2 その他のフラグへの影響
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* OptimizeStringConcatでStringBuilderを使わないとはどういうことか?
    * JITの世界なので、Javaのコンテキストを維持する必要はなく、直接メモリ上での結合処理に展開されるのではないか?

12.10 ラムダ式と匿名クラス
------------------------------------------------------------

* p.399 のサンプルコードに多数の間違い。
    * 以下のように書く必要があるはず。
        * 変数名の後に「=」が必要。
* ラムダ式で引数が空の場合は「() ->」でなければならない。
* 波カッコ内はステートメントなのでreturn文の後ろに「;」が必要。(直接式を書くなら波カッコとreturnは不要)

.. code-block:: Java

    IntegerInterface a3 = () -> { return 3; };
    IntegerInterface a2 = () -> { return 2; };
    IntegerInterface a1 = () -> { return 1; };

* p.400「ラムダ式では、呼び出しのたびにオブジェクトが生成されるということはありません。」⇒ ラムダ式でも、スコープの外側のローカル変数を参照すると新規のオブジェクトを作るのではないか?

12.10.1 ラムダ式と匿名クラスのロード
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

12.11 Streamとフィルタリングのパフォーマンス
------------------------------------------------------------

12.11.1 遅延アクセス
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* p.403 のサンプルコードに多数の間違い。
    * countはローカル変数なので、ラムダ式/匿名クラス内で書き換えることはできない。(final相当)
    * tが変数宣言されていないが、forEach()は返り値がないのでそもそも書いてあること自体が間違い。
        * collect()でCollectorsを使うのが定石。
* 最後の方のサンプルコードには間違いが多いが、ダウンロード版はどのようになっているのか?

* 次回の課題図書の投票は、1/9(土) 23:59まで。

(以上)


[ 戻る ]