Entity Framework + Postgresql + VACUUM の覚書

Entity Framework の Postgresql で VACUUM を行うと例外が発生します。
「25001: VACUUM cannot run inside a transaction block」

ソースコード:
using (ExecuteSqlCommand execute = new ExecuteSqlCommand(IPAddress,
                                                         Port,
                                                         DBName,
                                                         UserId,
                                                         Password))
{
    Database.ExecuteSqlCommand("VACUUM (ANALYZE) public.AAAA;");
}




どうすれば VACUUM が出来るようになるか。
ヒントはここにありました。
URL:https://stackoverflow.com/questions/926656/entity-framework-with-nolock

テーブル&行のロックを行わないトランザクションを開けば良いようです。
この様にトランザクションレベルを変更したうえでその中のトランザクションで行えばエラーにはなりません。
(Entity Framework内部処理で自動的にトランザクションが実行されてしまうのを防ぐため)

ソースコード:
using (ExecuteSqlCommand execute = new ExecuteSqlCommand(IPAddress,
                                                         Port,
                                                         DBName,
                                                         UserId,
                                                         Password))
{
    TransactionOptions transactionOptions = new TransactionOptions();
    transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted;
    using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.Required,
                                                                    transactionOptions))
    {
        Database.ExecuteSqlCommand("VACUUM (ANALYZE) public.AAAA;");
    }
}






最終的な完成したソース:

1.Postgresqlからユーザーテーブルのみを取得する
2.コネクションが残っていたら閉じる(isForcedフラグで強制的に閉じるかどうかを判断する)
3.トランザクションレベルをReadUncommittedに設定
4.全テーブルに対してVACUUM&ANALYZEを実行する

using (ExecuteSqlCommand execute = new ExecuteSqlCommand(IPAddress,
                                                         Port,
                                                         DBName,
                                                         UserId,
                                                         Password))
{
    var tableList = (from c in PgClass
                     join n in PgNamespace on new
                     {
                         a = c.Relnamespace
                     } equals new
                     {
                         a = n.Oid
                     }
                     where !(new String[] { "pg_catalog", "pg_toast", "information_schema" }.Contains(n.Nspname))
                     && c.Relkind == "r"
                     select new
                     {
                         tableName = n.Nspname + "." + c.Relname,
                     }).ToList();

    if (isForced && Database.Connection.State == System.Data.ConnectionState.Open)
    {
        Database.Connection.Close();
    }

    TransactionOptions transactionOptions = new TransactionOptions();
    transactionOptions.IsolationLevel = IsolationLevel.ReadUncommitted;
    using (TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.Required,
                                                                    transactionOptions))
    {
        foreach (var table in tableList)
        {
            Database.ExecuteSqlCommand("VACUUM (ANALYZE) " + table.tableName + ";");
        }
    }
}









検索用:Entity Framework Postgresql VACUUM Tranzaction Unlock バキューム ヴァキューム エラー VACUUM cannot run inside a transaction block

コメント

このブログの人気の投稿

ヨドバシカメラの店舗購入履歴を見るには…

C# の WPF の DataGrid で 行を交互に背景色を変える+選択色を変える+カラムが無い所も変える…

Visual Studio の ホットリロードが動かない場合に確認するところ