h2db – こみなのメモ帳 / 趣味と実益のネタ帳 Tue, 05 Aug 2025 14:40:20 +0000 ja hourly 1 https://wordpress.org/?v=6.1.1 H2DBのLinked Tablesについて調べてみた /archives/1670/ /archives/1670/#respond Tue, 05 Aug 2025 14:40:20 +0000 https://www.komina.info/?p=1670 H2DBにはLinked Tablesという機能があります。外部テーブル(ほかのDB)へのテーブルリンクを作成して、あたかも H2DB 内に存在するテーブルかのように扱う機能です。

JDBCドライバで接続できるDBであれば、以下のようなコマンドで利用可能です。

CREATE LINKED TABLE LINK('org.h2.Driver', 'jdbc:h2:./test2', 'sa', 'sa', 'TEST');

社内に MySQL PostgreSQL などいろんなDBサーバが乱立しているようなときに使ったら便利そう、ということで調べてみることにしました。

環境構築

docker-composeを使ってお試し環境を作ってみました。h2db + mysql + postgresql な環境です。githubに一式を公開してあります。

https://github.com/komina77/h2db

git clone https://github.com/komina77/h2db.git
cd LinkedTables
docker-compose up -d

サンプルデータは MySQL の公式サイトにあるサンプルデータworld)を利用させてもらうことにします。これを mysqlpostgresql の両方の初期データとしてインストールすることにします。(postgresql へはそのままの文法では食わせることはできなかったので少し書き換えています)

city, country, countryLanguage の3つのテーブルから構成されるデータベースになります。

MySQLを参照してみる

実はH2DBのサーバに内蔵されているWeb管理画面はH2DB以外のDBにも接続できますので、これを利用してみたいと思います。

ホストOS上のブラウザで、http://localhost:8082/ を開き、保存済設定の中から「Generic MySQL」を選びます。ドライバクラスなどのデフォルト設定が表示されるので、JDBC URLやユーザ名、パスワード(mysql/mysql)を入力します。接続テストが通れば成功です。

PostgreSQLを参照してみる

同様に PostgreSQL のデータベースも参照することができます。

オートコンプリート機能も有効で、ちょっとしたSQLならすぐに試してみることができます。PostgreSQLの大文字小文字混在のカラムはダブルコーテーションで囲わないといけないので、逆に不便でした。

Linked Tables を定義してみる

mysqlpostgresql の準備ができたところで H2DB に接続して Linked Tables を作成してみたいと思います。

まずは mysqlworldデータベースの中の countryテーブルを my_country という名前で参照できるようにしてみます。

CREATE LINKED TABLE IF NOT EXISTS MY_COUNTRY(
'com.mysql.jdbc.Driver', 'jdbc:mysql://mysql-1:3306/world', 'mysql', 'mysql', 'country'
);

これだけで MY_COUNTRY というテーブルをローカルにあるテーブルのように参照できるようになります。

同様に、PG_CITYPG_COUNTRYLANGUAGE についてもテーブルを定義します。

CREATE LINKED TABLE IF NOT EXISTS PG_CITY(
'org.postgresql.Driver', 'jdbc:postgresql://postgres-1/world', 'postgres', 'postgres', 'city'
);

CREATE LINKED TABLE IF NOT EXISTS PG_COUNTRYLAUNGUAGE(
'org.postgresql.Driver', 'jdbc:postgresql://postgres-1/world', 'postgres', 'postgres', 'countrylanguage'
);

どんなSQLが発行されているか(MySQL

まずは条件なしで検索。

SELECT * FROM MY_COUNTRY 
SELECT * FROM country T

次は簡単な条件を付けてみます。

SELECT * FROM MY_COUNTRY where CODE ='JPN'
SELECT * FROM country T 
WHERE CODE>='JPN' AND CODE<='JPN'

単純な文字列の等号による一致条件のつもりだったのですが不等号の範囲検索に変換されてしまいました。なにか意図があるのでしょうがとりあえずヨシとします。

どんなSQLが発行されているか(PostgreSQL

SELECT * FROM PG_CITY 
SELECT * FROM public.city T
SELECT * FROM PG_CITY 
WHERE ID =10
SELECT * FROM public.city T 
WHERE ID>=$1 AND ID<=$2
ERROR:  column "id" does not exist at character 35

おっと。エラーが出てしまいました。どうやらDDLの段階でカラム名をダブルコーテーションで囲って大文字小文字を厳密に定義していたことが原因と思われる。。

DDLを修正してもう一度やり直し。PG_CITYPG_COUNTRYLANGUAGE についてもテーブル定義をやり直します。

SELECT * FROM PG_CITY 
WHERE ID =10
SELECT * FROM public.city T 
WHERE ID>=$1 AND ID<=$2
DETAIL:  parameters: $1 = '10', $2 = '10'

無事にクエリを発行することができました。

結合したらどうなるか(異DB同士

テーブル一つに対するクエリであれば、ほぼ等価の条件式が渡されるようなので、リンクされた側のDBで適切な実行計画が適用されることになりそうです。

では、2つのDBにまたがる結合をしたらどうなるのか。やってみたいと思います。

SELECT T1.NAME, T2.LANGUAGE  FROM MY_COUNTRY  T1
INNER JOIN PG_COUNTRYLAUNGUAGE  T2
ON T2.COUNTRYCODE = T1.CODE
AND  T2.ISOFFICIAL ='T'
WHERE T1.REGION  = 'North America'
;

北アメリカの国における公用語は?、という感じの意味合いになります。まず MY_COUNTRY を北アメリカで絞り込んだのち、国コードで PG_COUNTRYLANGUAGE から公用語を得る、という結合になることを想定してみました。

MySQL

SELECT * FROM country T WHERE CODE>='ABW' AND CODE<='ABW'
SELECT * FROM country T WHERE CODE>='AFG' AND CODE<='AFG'
SELECT * FROM country T WHERE CODE>='AFG' AND CODE<='AFG'
SELECT * FROM country T WHERE CODE>='AIA' AND CODE<='AIA'
SELECT * FROM country T WHERE CODE>='ALB' AND CODE<='ALB'
SELECT * FROM country T WHERE CODE>='AND' AND CODE<='AND'
SELECT * FROM country T WHERE CODE>='ANT' AND CODE<='ANT'
SELECT * FROM country T WHERE CODE>='ANT' AND CODE<='ANT'
SELECT * FROM country T WHERE CODE>='ARE' AND CODE<='ARE'
SELECT * FROM country T WHERE CODE>='ARG' AND CODE<='ARG'
SELECT * FROM country T WHERE CODE>='ARM' AND CODE<='ARM'
:
:

PostgreSQL

SELECT * FROM public.countrylanguage T WHERE ISOFFICIAL>=$1 AND ISOFFICIAL<=$2
-- parameters: $1 = 'T', $2 = 'T'

どうやら想定と逆に、PG_COUNTRYLANGUAGE から公用語の一覧を取得したのち、対応する国の一覧を取得。クエリには北アメリカでの絞り込みは入っていないので H2DB側で一番最後に行われたようです。

実行計画を見てみる

事後になりますが H2DBでの実行計画を見てみます。

EXPLAIN
SELECT T1.NAME, T2.LANGUAGE  FROM MY_COUNTRY  T1
INNER JOIN PG_COUNTRYLAUNGUAGE  T2
ON T2.COUNTRYCODE = T1.CODE
AND  T2.ISOFFICIAL ='T'
WHERE T1.REGION  = 'North America'
;
SELECT
    "T1"."NAME",
    "T2"."LANGUAGE"
FROM "PUBLIC"."PG_COUNTRYLAUNGUAGE" "T2"
    /* PUBLIC."": ISOFFICIAL = 'T' */
    /* WHERE T2.ISOFFICIAL = 'T'
    */
INNER JOIN "PUBLIC"."MY_COUNTRY" "T1"
    /* PUBLIC."": CODE = T2.COUNTRYCODE */
    ON 1=1
WHERE ("T1"."REGION" = 'North America')
    AND (("T2"."ISOFFICIAL" = 'T')
    AND ("T2"."COUNTRYCODE" = "T1"."CODE"))

FROM句で指定していたテーブルが MY_COUNTRY から PG_COUNTRYLANGUAGE に変わっていますね。H2DB では結合順序指定するヒント句はサポートされていません。性能を高めるには希望する結合順になるまで SQLをこねくり回すしかなさそうです。

結合したらどうなるか(同DB同士

同じDBにあるテーブル同士の結合も試してみます。

EXPLAIN
SELECT T1.COUNTRYCODE ,T1.DISTRICT , T1.NAME , T2.LANGUAGE
FROM PG_CITY T1
INNER JOIN PG_COUNTRYLAUNGUAGE T2
ON T2.COUNTRYCODE =T1.COUNTRYCODE 
WHERE T1.POPULATION >7000000
AND T2.ISOFFICIAL ='T'
;
SELECT
    "T1"."COUNTRYCODE",
    "T1"."DISTRICT",
    "T1"."NAME",
    "T2"."LANGUAGE"
FROM "PUBLIC"."PG_CITY" "T1"
    /* PUBLIC."": POPULATION > 7000000 */
    /* WHERE T1.POPULATION > 7000000
    */
INNER JOIN "PUBLIC"."PG_COUNTRYLAUNGUAGE" "T2"
    /* PUBLIC."": COUNTRYCODE = T1.COUNTRYCODE */
    ON 1=1
WHERE ("T2"."COUNTRYCODE" = "T1"."COUNTRYCODE")
    AND (("T1"."POPULATION" > 7000000)
    AND ("T2"."ISOFFICIAL" = 'T'))

人口が700万人超の都市のある国の公用語の一覧を得るクエリです。PostgreSQL へは以下のクエリが送信されました。

SELECT * FROM public.city T WHERE POPULATION>=$1
-- parameters: $1 = '7000000'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'BRA', $2 = 'BRA'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'GBR', $2 = 'GBR'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'IDN', $2 = 'IDN'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'IND', $2 = 'IND'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'IND', $2 = 'IND'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'JPN', $2 = 'JPN'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'CHN', $2 = 'CHN'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'CHN', $2 = 'CHN'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'KOR', $2 = 'KOR'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'MEX', $2 = 'MEX'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'PAK', $2 = 'PAK'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'TUR', $2 = 'TUR'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'RUS', $2 = 'RUS'
SELECT * FROM public.countrylanguage T WHERE COUNTRYCODE>=$1 AND COUNTRYCODE<=$2
-- parameters: $1 = 'USA', $2 = 'USA'

700万人超の都市の一覧を取得したのち、国コードを使って1国ずつ PG_COUNTRYLANGUAGE を取得していますね。ISOFFICIAL については記載がないので H2DB側で絞り込みを行っているのでしょう。

同じDBにあるテーブルであっても、結合をそのDBに任せず H2DB内で行っていることが分かりました。

まとめ

  • H2DB には他のDBのテーブルをH2DB内のテーブルのように見せかける機能がある。複数のシステムのDBを透過的に扱うのに便利。
  • 外部DBのテーブル定義に依存する。カラム名に大文字小文字混在を許すようなテーブルを参照するときは失敗することがあるので、事前に調査してビューなどを介すなど工夫が必要。
  • テーブル1つに対するクエリであればテーブルを持つDB上で抽出が行われるので、性能的には問題なさそう。
  • リンクテーブル同士での結合はサポートされている。しかし、H2DBの判断で実行計画が決まってしまうので性能が出ないことがある。
  • 結合するリンクテーブルが同じDBのテーブルであっても、結合がリンク先のDBに任されない。H2DBの判断によって行われる。

異なるシステムで使われているDBのテーブルを一時的に参照するような用途では便利かもしれない。しかし、複雑なクエリで問い合わせるときは性能を出すために苦労することになりそうだ。

]]>
/archives/1670/feed/ 0
[h2db]サーバモードについて /archives/740/ /archives/740/#respond Thu, 25 Mar 2021 21:00:00 +0000 https://www.komina.info/?p=740 java -cp %PLAY_HOME%\framewo […]]]> H2DBは組込モードだけでなくサーバモードでも起動することができる。以下のような感じで、org.h2.tools.Server を実行すればサーバが起動する。

> java -cp %PLAY_HOME%\framework\lib\h2-1.4.185.jar org.h2.tools.Server

起動するとTCPポートやWebコンソールのポート情報が表示されるので、その情報を使ってアクセスする。

サーバ機能には3種類あり、-tcp, -pg, -webオプションを指定しないと全て起動する。一つでも指定すると個別起動となる。

ポートオプション
標準TCPサーバ9092-tcp 機能使用
-tcpSSL SSL使用
-tcpPort ### ポート指定
-tcpPassword *** 管理者パスワード指定
-tcpAllowOthers 他PCからの接続許可
-tcpDaemon デーモンスレッド起動
-key *** ODBC用
-ifExists ifExists機能ON
-baseDir *** ベースディレクトリ指定
Postgres互換PGサーバ5435-pg 機能使用
-pgPort ### ポート指定
-pgAllowOthers 他PCからの接続許可
-pgDaemon デーモンスレッド起動
-key *** ODBC用
-ifExists ifExists機能ON
-baseDir *** ベースディレクトリ指定
Web管理画面Webブラウザから使える管理画面8082-web 機能使用
-browser ブラウザ起動
-webSSL SSL使用
-webAllowOthers 他PCからの接続許可
-webDaemon デーモンスレッド起動
サーバ種類について

その他オプション -trace トレースON

JavaプログラムからTCPサーバ起動する

	String serverOptions[] = new String[] { "-tcpAllowOthers" };
	org.h2.tools.Server h2Server = org.h2.tools.Server.createTcpServer(String...);
	h2Server.start();
	Logger.info("Connect to 'jdbc:h2:%s'.)", h2Server.getURL());

サーバ接続文字列

jdbc:h2:tcp://[サーバーのIP]/[データベースファイル]

playframework1の場合

db.default.url=jdbc:h2:tcp://localhost/${application.path}/db/h2/play;MODE=MYSQL;MVCC=TRUE;
db.default.driver=org.h2.Driver
db.default.user=sa
db.default.pass=
#サーバ側のベースディレクトリに依存する接続文字列の書き方
#db.default.url=jdbc:h2:tcp://localhost/db/h2/play;MODE=MYSQL;MVCC=TRUE;
#h2server.baseDir=${application.path}

#サーバ側のベースディレクトリに依存しない書き方
#db.default.url=jdbc:h2:tcp://localhost/C:/temp/db/h2/play;MODE=MYSQL;MVCC=TRUE;

#サーバ側のベースディレクトリ設定と接続文字列のディレクトリ設定が重なった場合
# サーバ側で指定したディレクトリ配下を指定したなら問題なく使える。
# サーバ側で指定したディレクトリ外を指定した時は例外が出て止まってしまう。

ODBC用機能

-key オプションはODBCのDB名とDBURLとのマッピングを行う。らしい。

ODBC Driver
To map an ODBC database name to a different JDBC database name, use the option -key when starting the server.

http://www.h2database.com/html/advanced.html#odbc_driver

サーバとクライアントでH2のバージョン違いでエラーが発生することがある。

"unexpected status 16777216"

]]>
/archives/740/feed/ 0
[h2db]結果セットの返却について /archives/738/ /archives/738/#respond Wed, 24 Mar 2021 21:00:00 +0000 https://www.komina.info/?p=738 デフォルトの動作は、データが見つかり次第返却する方式ではなく、全件抽出してからの返却となる。そのため、件数が多いと最初のデータが返ってくるまでちょっと待たされることがある。

件数の多いデータを一気に取得するのを是とするかはまた別の議論だが、随時取得を行うオプションもある。

SET LAZY_QUERY_EXECUTION TRUE;

あるいは接続文字列に “LAZY_QUERY_EXECUTION=1;” を追加する。

H2 query taking a long time on “SELECT * FROM test” , and ResultSet not streaming from table as sqlite does

https://groups.google.com/g/h2-database/c/rgpD_y3Xp7w

組込モードでのみ動作する。遅延結果セットを開いている接続に何かするは避けるべき。デッドロックやリーク、その他バグの原因になるかも。とのこと。

]]>
/archives/738/feed/ 0
[h2db]クラスタリング /archives/736/ /archives/736/#respond Tue, 23 Mar 2021 21:00:00 +0000 https://www.komina.info/?p=736 サーバモード限定。非常に簡素だがクラスタリングをサポートしている。組込みモードは対象外。

  • サーバは2台固定。
  • 参照系クエリは1番目ノードに、それ以外のクエリは両方のノードに対して実行される。結果が不定なランダム関数はノード毎に違う値が発生するので注意が必要。

ノード1が停止してもノード2が生きていれば使い続けられるが、その後ノード1が復活したとしてもノード2へ向いた接続はそのままなので、次にノード2が停止すると接続が切れてしまう。

正→副への切り替えは自動で行われるが、副→正への切り替えは出来ない。再接続しなくてはならない。

乱数のようなサーバによって結果が変わるような関数は、INSERTやUPDATEに使用するとデータに差が生じてしまう。シーケンス値のオートインクリメントやID列も同様の理由で使用してはいけない。手動でシーケンス値を要求して、その値を持って更新を行う必要がある。

正直、制約が多くて不便。微妙な感じです。

Clustering / High Availability
This database supports a simple clustering / high availability mechanism.

http://h2database.com/html/advanced.html#clustering

クラスタの検出SQL

SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME='CLUSTER'

]]>
/archives/736/feed/ 0
[h2db]別のDBとの連携について /archives/732/ /archives/732/#respond Sun, 21 Mar 2021 21:00:00 +0000 https://www.komina.info/?p=732 他のDBのテーブルを透過的に扱うことができるリンクテーブルという仕組みがあります。

Linked Tables
This database supports linked tables, which means tables that don’t exist in the current database but are just links to another database.
You can then access the table in the usual way. Whenever the linked table is accessed, the database issues specific queries over JDBC.

http://h2database.com/html/advanced.html#linked_tables

下記のようにCREATEコマンドでテーブルを作成する形になります。

CREATE LINKED TABLE AAAA('org.postgresql.Driver', 'jdbc:postgresql:test', 'sa', 'sa', 'BBBB');
項目説明
AAAA参照用のテーブル名エイリアス
第一引数接続用JDBCドライバ
第二引数JDBC接続文字列
第三引数ユーザ名
第四引数パスワード
第五引数接続先のテーブル名

例えばH2DBで下記SQLを実行すると、

SELECT * FROM AAAA WHERE ID=1

接続先のDBで下記のように置き換えられて実行されます。

SELECT * FROM BBBB WHERE ID=1

ちょっと思いつく用途としてはCSV出力。H2DBのCSVファイル出力する機能をほかのDBでも甘受することができますね。

call csvwrite('out.csv', 'select * from AAAA');

他にも、商用稼働しているDBをリンクテーブル経由でデータを拝借して、自前ツールで加工、ローカルDBへ格納、みたいな使い方を思いつきました。

]]>
/archives/732/feed/ 0
[h2db]稼働中のバックアップ /archives/729/ /archives/729/#respond Sat, 20 Mar 2021 21:00:00 +0000 https://www.komina.info/?p=729 稼働中のデータベースをバックアップするときは、次のコマンドを手動またはプログラムから実行すればよい。

SQL> backup to '/tmp/fo.zip'

参考までに下記ページには、Hibernateからバックアップを実行する方法が書かれています。

H2 Database Online Backup in an Spring, Hibernate ORM Solution with EntityManagers as persistenceUnits

https://groups.google.com/g/h2-database/c/ri3SiqWezkM

もちろん稼働中でないときはデータベースのファイルをコピーするだけでOKです。

]]>
/archives/729/feed/ 0
[h2db]インデックスのリビルド /archives/727/ /archives/727/#respond Fri, 19 Mar 2021 21:00:00 +0000 https://www.komina.info/?p=727 一般にデータの更新を繰り返しているとインデックスが断片化、肥大化しまいます。H2DBも例外ではありません。そうしたインデックスをリビルド(再構築)する機能は現時点(2021/03/18)で実装されていません。

データベースを停止することができるのであれば、リカバリの手順と同じく、データをスクリプトとして出力、データベースを削除してスクリプトからデータを投入しなおすのがシンプルで良さそうです。データ登録の過程で自然にインデックスが作られていきます。

定期的にバックアップを取るのであれば、そのついでに行えば一石二鳥かもしれないです。

ロードマップには挙がっているので気持ちはあるみたいですが、優先度2の項目となのであまり期待できなさそうです。

Priority 2
・Rebuild index functionality to shrink index size and improve performance.

http://www.h2database.com/html/roadmap.html

リビルド機能があればデータベースを停止せずにインデックスを再構築できるってことなんでしょうが、そこまでの連続稼働が求められるシステムであればH2DBは選択肢から外した方がいいですね。市販のRDBを探した方がいいでしょう。

]]>
/archives/727/feed/ 0
[h2db]マイグレーションとリカバリ /archives/722/ /archives/722/#respond Wed, 10 Mar 2021 21:00:00 +0000 https://www.komina.info/?p=722 H2のバージョンアップで、DBデータ形式に関する変更があった場合でもDBデータを自動的にバージョンアップしてくれません。jarを差し替える前にDBデータの移行作業が必要です。

移行作業というと仰々しいですが、リカバリの手順と同じです。バージョンアップ前にデータをSQLとして出力しておいて、バージョンアップ後にデータを再構築します。

リカバリのツールはjarに同梱されているのでクラス指定でコマンドラインより実行します。

DBファイルのあるディレクトリに移動したのち、このDBへの接続に使用しているバージョンのh2.jarをクラスパスに指定して下記コマンドを実行します。

C:\h2db> java -cp C:\Tools\h2-1.4.195.jar org.h2.tools.Recover

SQLファイルが出力されていれば成功です。

出力されたSQLから新しいバージョンのDBを再構築するには、下記コマンドのようにします。

C:\h2db> java -cp C:\Tools\h2-1.4.196.jar org.h2.tools.RunScript -url jdbc:h2:C:/h2db/db/h2/play;MODE=MYSQL; -user sa2 -script play.h2.sql  -showResults

JDBC文字列を指定したり、sqlファイルを指定するのがポイントです。

]]>
/archives/722/feed/ 0
[h2db]参照専用DBの作り方 /archives/641/ /archives/641/#respond Mon, 18 Jan 2021 21:00:00 +0000 https://www.komina.info/?p=641

If the database files are read-only, then the database is read-only as well. It is not possible to create new tables, add or modify data in this database. Only SELECT and CALL statements are allowed.

Features (h2database.com)

ファイルをReadOnlyにするだけでOK。
プログラム側からは Connection.isReadOnly() で判定可能。
CALL READONLY() というSQLコマンドでも制御可能。

ZIPやJARファイルの中のDBファイルも扱える。

When the zip file is created, you can open the database in the zip file using the following database URL:
jdbc:h2:zip:~/data.zip!/test

Features (h2database.com)

]]>
/archives/641/feed/ 0
[h2db]コンパクションの方法 /archives/638/ /archives/638/#respond Sat, 16 Jan 2021 21:00:00 +0000 https://www.komina.info/?p=638 データを登録するとファイルサイズがどんどん大きくなる。
データの削除などで生じたファイル内の空きスペースは自動的に再利用される。

データベースを閉じるとき、デフォルトで200ミリ秒までの範囲で空きスペースの圧縮を試みるが、それ以上の圧縮を望むのであれば、SHUTDOWN CONMAPCTコマンドを使用する。

コンパクション操作はshutdownコマンドでのコネクション切断と共に指定する。

コマンド説明
shutdown compactシャットダウン時にコンパクションを行う。MAX_COMPACT_TIME(ミリ秒)で処理時間上限が決まる。MAX_COMPACT_TIMEはDBオープン時に指定する。
中途半端に短い時間だと作業が完了しないばかりかサイズが増えることもあるので注意。
例) jdbc:h2:C:/db/h2/play;MODE=MYSQL;MAX_COMPACT_TIME=10000
shutdown defragシャットダウン時にページの並べ替えを行う。検索が速くなる可能性あり。
shutdown immediatelyデータベースのクリーンアップやコンパクションなど何もせずにシャットダウンする。

ちなみに、データベースを再作成すれば、索引がリビルドされてデータベースのサイズが更に小さくなる可能性がある。

データベース接続中の圧縮(Vacuum)できない。取り込みたい機能として挙がっているが最優先ではないとのこと。
常時稼働するような用途には向かない理由の一つ。

]]>
/archives/638/feed/ 0