web-dev-qa-db-ja.com

GDAL / OGR ogr2ogrを使用して多くのジオメトリレコードを挿入すると、アプリドメインがアンロードされる

  • SQL Server 2012 x64、割り当てられた合計メモリ2GB、「AppDomain unloaded」の問題をより迅速に再現できるように低い値に設定

  • Windows Server 2012、サーバー上の合計メモリ16GB

(本番環境では、合計64 GBのメモリがあり、必要に応じてSQL Serverがすべてを使用できますが、このAppDomainのアンロードの問題は引き続き発生します)

SQL Serverは、割り当てられた2GBのメモリがいっぱいになると、AppDomainをアンロードし続けます。

  1. sQL Serverが使用している既存のメモリを「再利用」しないのはなぜですか(または、既存のAppDomainにハングアップして、既存のAppDomainに使用されているメモリを削減しないのですか)。

  2. それとも、AppDomainをアンロードしてメモリを再利用することで、SQLServerが機能する方法ですか?

    • 挿入クエリは関数geometry :: STGeomFromTextを使用し、

    • 約1,000,000の挿入があります、

    • それぞれ200挿入のトランザクションでコミットされ、次のようになります。

      INSERT INTO [dbo].[gdb2] ([ogr_geometry],
          [seg_num], [par_num], [segpar], [par_ind], [prc], [parish], [county], [lac], [shire_name], [feat_name], [loc], [locality], [parcel_typ], [cover_typ], [acc_code], [ca_area_sqm], [shape_length], [shape_area], [globalid]) 
      VALUES (geometry::STGeomFromText('MULTIPOLYGON (((503754.43209999986 6952046.6778,503770.5603 6952043.9964,503790.83380000014 6952040.6264,503810.62700000033 6952037.3364,503824.2081000004 6952035.0799,503825.46609999985 6952014.4771,503805.18599999975 6952017.8472,503786.3114 6952020.9851,503766.46679999959 6952024.2841,503746.6699000001 6952027.5757,503754.43209999986 6952046.6778)))',28356).MakeValid(),
          26332, 84, 26332084, 81, 6000, 'OBSOLETE', 'OBSOLETE', 1000, 'CITY', 'AVENUE', 2449, 'SALISBURY', 'R', 'B', 31, 1516.137, 191.870950878815, 1514.92744496079, '{6A0865B9-3D4A-4395-BC78-B2E16CF4E95B}')
      

更新
@ codyに感謝します。はい、2GBでは十分ではありませんが、本番環境では64GBであり、SQLServerの方がはるかにビジーであるだけではまだ十分ではありません。

メモリを4 GBに増やすと、必然的に延期され、AppDomainがアンロードされます。

メモリを8GBに設定するだけで問題が解決し、AppDomainの問題は解決します。ただし、本番SQLServerでは、アプリ用に8GBを取得できず、サーバーは非常にビジーであり、SQLServerは最終的にAppDomainをアンロードしました。

更新2
-問題を再現するためのスクリプト
-2GB RAMの場合、40Mループに増加し、通常は27M機能が挿入されたときに失敗します

更新3
-以下のスクリプトは問題を再現しません、
-WellKnownText/WKTをSQLServerにアップロードするogr2ogr.exeのみがそれを行います。

USE [test_appDomainUnload]
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[test_appDomainUnload](
[ogr_geometry] [geometry] NULL,
[id] [bigint] IDENTITY(1,1) NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

DECLARE @i bigint = 0

WHILE @i < 40000000
BEGIN
    SET @i = @i + 1
    BEGIN TRANSACTION
        /* do some work */
        INSERT INTO [dbo].[test_appDomainUnload] ([ogr_geometry]) 
        VALUES (geometry::STGeomFromText('MULTIPOLYGON (((503754.43209999986 6952046.6778,503770.5603 6952043.9964,503790.83380000014 6952040.6264,503810.62700000033 6952037.3364,503824.2081000004 6952035.0799,503825.46609999985 6952014.4771,503805.18599999975 6952017.8472,503786.3114 6952020.9851,503766.46679999959 6952024.2841,503746.6699000001 6952027.5757,503754.43209999986 6952046.6778)))',28356).MakeValid())
    COMMIT
END

更新4
データの添付(FileGDB)、ogr2ogr.exeバイナリとogr.bat実行します。編集ogr.batデータベースのパラメータを設定して実行します。

https://drive.google.com/open?id=0By7mVmnZ1C1oT0lWVTJaZmlabTAogr binaries1

更新5
明確にするために、ogr2ogr.exeは次の場所にあります:

私たちはv1.11を使用します http://github.com/OSGeo/gdal/blob/1.11/gdal/apps/ogr2ogr.cpp

トランク http://github.com/OSGeo/gdal/blob/trunk/gdal/apps/ogr2ogr_bin.cpp

sQLServerマシンとは別の別のPCで実行されます。

更新6
正確なエラーメッセージ:

time + 0:メモリ不足のため、AppDomain 9(master.sys [runtime] .8)がアンロード用にマークされています。
time + 1:AppDomain 9(master.sys [runtime] .8)がアンロードされました。
time + 2:AppDomain 10(master.sys [runtime] .9)が作成されました。

すでにAppDomain 9、以前の8つのAppDomain(すべてmaster.sys[runtime])がアンロードされ、再作成されました。

3
Don Ch

Log\ERRORLOGファイルからexactメッセージを提供すると、複数のAppDomainと、AppDomainがアンロードされる複数の理由があるため、非常に役立ちます。

さまざまなAppDomainに関して、組み込みのCLRベースの機能用に作成されたAppDomainがあります。たとえば、特定の関数(たとえば、master)や特定のタイプ(たとえば、FORMAT)が使用されたときにGEOMETRYに表示されるものなどです。また、作成したアセンブリにあるカスタムSQLCLRコードにアクセスすると、ユーザーデータベースにAppDomainが作成されます。

「システム」AppDomainのアンロードは、最悪の場合、かなり頻繁に発生する場合にのみパフォーマンスの問題になるはずです。それがたまにしか起こらない場合、それは本当にただの迷惑です。

カスタムSQLCLRコードが静的クラス変数を介して共有メモリを使用している場合、「ユーザー」のAppDomainのアンロードは、エラーや予期しない動作を引き起こす可能性があります。

AppDomainsがアンロードされるさまざまな理由については、次のようなものを実行したことが原因である可能性があります。

_DBCC FREESYSTEMCACHE('ALL');
_

その結果、次のメッセージが表示されます。

AppDomain xx(master.sys [runtime] .yy)は、共通言語ランタイム(CLR)またはセキュリティデータ定義言語(DDL)操作により、アンロード用にマークされています。

AppDomainsがアンロードされるより一般的な理由、およびこの質問の主題である可能性が高いのは、「メモリプレッシャー」が原因です。メモリプレッシャーとは、利用可能な物理メモリの量が減少し、アプリケーションがメモリをより積極的に解放する指標として使用される場合です。 SQL Serverは、プランキャッシュからアイテムをクリアし、AppDomainをアンロードすることにより、メモリを解放します。

メモリの圧迫の原因は、必ずしもSQL Server内でのCLRベースの機能の使用ではありません。SQLServerの内部でも外部でも、SQL Serverに関係のないシステムで実行されているものはすべて、メモリを使い果たしてメモリの圧迫を引き起こす可能性があります。 「メモリプレッシャー」の詳細については、MSDNの記事 Plan Cache Internals を参照してください。

質問のpdateで提供される情報から:

以下のこのスクリプトは問題を再現しません。WellKnownText/ WKTをSQLServerにアップロードするogr2ogr.exeのみがそれを行います。

ogr2ogr.exeプログラムは、どういうわけか大量のメモリを取得し、それを十分に迅速に解放しない(またはおそらくまったく?)これは、不適切なプログラミング方法など、いくつかの理由が原因である可能性がありますが、ソースコードを確認できない限り、絞り込むのは困難です。そして、たとえソースコードを見ることができたとしても、これがオープンソースであり、変更を加えて再コンパイルできなければ、それについてできることは多くありません。あるいは、この問題はogr2ogr.exeの開発者に報告して、だれがそれを修正できるかを知ることができます。


追伸質問のテストコードは、実行されている操作としての質問の説明を正確に表したものではありません。

約1,000,000の挿入があり、それぞれ200挿入のトランザクションでコミットされます。

サンプルコードでは、トランザクションごとにステートメントが1つしかないため(明示的なトランザクションでさえも本当の理由はありません)。

記述されている動作をより綿密にテストするには、投稿されたテストコードを次のように変更します。

_SET ANSI_NULLS, QUOTED_IDENTIFIER, NOCOUNT ON;

DECLARE @i INT = 0;

BEGIN TRAN;
WHILE (@i < 40000000)
BEGIN
    SET @i = @i + 1;

    IF(@i % 100 = 0) -- Print message every 100 iterations
    BEGIN
        RAISERROR('%d -- %d', 10, 1, @i, @@TRANCOUNT) WITH NOWAIT;
    END;

    INSERT INTO [dbo].[test_appDomainUnload] ([ogr_geometry]) 
    VALUES (geometry::STGeomFromText('MULTIPOLYGON (((503754.43209999986 6952046.6778,
            503770.5603 6952043.9964,503790.83380000014 6952040.6264,
            503810.62700000033 6952037.3364,503824.2081000004 6952035.0799,
            503825.46609999985 6952014.4771,503805.18599999975 6952017.8472,
            503786.3114 6952020.9851,503766.46679999959 6952024.2841,
            503746.6699000001 6952027.5757,503754.43209999986 6952046.6778)))',
           28356).MakeValid());

    IF(@i % 200 = 0) -- COMMIT every 200 iterations
    BEGIN
        COMMIT TRAN;
        BEGIN TRAN;
    END;
END;

IF (@@TRANCOUNT > 0) -- run manually if you cancel the query
BEGIN
    COMMIT TRAN;
END;
_

注:クエリをキャンセルする場合は、最後のIFブロックを手動で実行して、トランザクションが開いたままにならないようにする必要があります。

私のテストシステム(SSMSやVisual Studioなどでも使用するため、空きメモリがほとんどありません)では、survived_memory_kbsys.dm_clr_appdomains のフィールドが_1_。 (そしてtotal_allocated_memory_kbフィールドは、current割り当て値ではなく、行われたすべてのメモリ割り当ての合計であるため、信頼できるメトリックとして使用しません。)

[〜#〜]更新[〜#〜]

提供された新しい情報は、ogr2ogr.exeがSQL Serverとは異なるマシンで実行されており、TCP経由で接続していることを示しています。これは、問題が接続に関連している可能性があることを示しています(接続プーリングが使用されていますか?トランザクションは単一の接続または新しい接続で毎回処理されていますか?新しい接続の場合、アプリは接続オブジェクトを解放して、接続を確立できます。閉まっている?)。

または、メモリ使用量はINSERTクエリの送信方法に関連している可能性があります。パラメータ化されたクエリはキャッシュに単一のプランを持ち、各INSERTごとに再利用されますが、クエリがアドホック(つまり、新しい値)各INSERTごとに連結される)場合、プランキャッシュの膨張を引き起こす可能性があります。以下のリソースが調査に役立ちます。

最初のリンクは、単一のDBでプランキャッシュをフラッシュするDBCCコマンドを示しています(インスタンス全体のキャッシュをクリアするよりも少し安全です)。

_DBCC FLUSHPROCINDB (<dbid>)
_

しかし、このDBCCコマンドは他の方法では文書化されていないようです。

簡単な十分なテストは、テストシステムでogr2ogr.exeを実行し、実行中にDBCC FLUSHPROCINDB (<dbid>)を数回実行して、消費されたメモリの合計がこれまでに到達するかどうかを確認することです。あなたが見てきたもの。

更新2

少なくともv1.11では、行1041以降、アドホック(つまり、パラメータ化されていない)SQLが使用されていることを確認しました。

gdal/gdal/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialtablelayer.cpp(ブランチ1.11)

また、v2.0で一括アップロードのサポートが追加されたようです。したがって、おそらく最新バージョン(現在は2.1)にアップグレードする必要があります。

更新

問題がPlan Cache Bloatを処理している場合、テストコード(上記の私の適応でも)は適用されません。同じINSERTステートメントを毎回再利用するため、キャッシュ。これを念頭に置いて、動的SQLを使用して毎回INSERTステートメントを変更するようにテストコードをさらに調整しました。

_-- SELECT COUNT(*) FROM dbo.test_appDomainUnload;
-- TRUNCATE TABLE dbo.test_appDomainUnload;
-- CHECKPOINT;

SET ANSI_NULLS, QUOTED_IDENTIFIER, NOCOUNT ON;

DECLARE @i INT = 0,
        @SQL NVARCHAR(MAX);

BEGIN TRAN;
WHILE (@i < 40000000)
BEGIN
    SET @i = @i + 1;

    IF(@i % 100 = 0) -- Print message every 100 iterations
    BEGIN
        RAISERROR('%d -- %d', 10, 1, @i, @@TRANCOUNT) WITH NOWAIT;
    END;

    SET @SQL = N'
    INSERT INTO [dbo].[test_appDomainUnload] ([ogr_geometry]) 
    VALUES (geometry::STGeomFromText(''MULTIPOLYGON (((503754.' +
            CONVERT(NVARCHAR(15), @i) + N' 6952046.6778,
            503770.5603 6952043.9964,503790.83380000014 6952040.6264,
            503810.62700000033 6952037.3364,503824.2081000004 6952035.0799,
            503825.46609999985 6952014.4771,503805.18599999975 6952017.8472,
            503786.3114 6952020.9851,503766.46679999959 6952024.2841,
            503746.6699000001 6952027.5757,503754.' +
            CONVERT(NVARCHAR(15), @i) + N' 6952046.6778)))'',
           28356).MakeValid());
         ';
    EXEC(@SQL);

    IF(@i % 200 = 0) -- COMMIT every 200 iterations
    BEGIN
        COMMIT TRAN;
        BEGIN TRAN;
    END;
END;

IF (@@TRANCOUNT > 0) -- run manually if you cancel the query
BEGIN
    COMMIT TRAN;
END;
_

数が次のように増えるのを見てください:

_SELECT name, pages_in_use_kb , pages_kb
FROM sys.dm_os_memory_cache_counters
WHERE type = 'CACHESTORE_SQLCP';

SELECT COUNT(*) AS [TotalNumberOfCachedPlans]
FROM sys.dm_exec_cached_plans;
_

masterのAppDomainを強制的にアンロードすることはできませんでしたが、確実に近づいています。

最終更新

O.P.は、UPDATE 2の提案が機能したと報告しました。

BCPをサポートしてogr2ogr.exeを再構築し、BCPを利用してSQLServerにインポートすると、このAppDomainのアンロードされた問題が解消され、SQLServerの最大メモリ設定を1GBに下げることもでき、すべてが正常に実行されます。

3
Solomon Rutzky