2017-04-25 4 views
1

プロファイルの写真をデータベースに保存し、これらの写真をどこかのディスクにエクスポートする小さなC#コンソールアプリケーションを作成しました。私は、ループ内で一度に10枚の写真を選択します。ブロブを選択するとすべてのクエリがタイムアウトするまでMySQLサーバが遅くなります

const int pageSize = 10; 

using (var connection = new MySqlConnection(_options.Connectionstring)) 
{ 
    connection.Open(); 
    var pageCount = pageSize; 

    for (var page = 0; pageCount == pageSize; page++) 
    { 
     using (var command = new MySqlCommand($"SELECT 
       p.FirstName, p.LastName, p.Department, ph.Data 
      FROM Persons p 
      INNER JOIN Photos ph ON ph.PersonId = p.Id 
      LIMIT {pageSize} OFFSET {page * pageSize}", connection) 
     using (var reader = command.ExecuteReader()) 
     { 
      for (pageCount = 0; reader.Read(); pageCount++) 
      { 
       var path = GetFilePath(reader, _options.Pattern); 
       EnsureDirectoryExists(path); 
       File.WriteAllBytes(path, (byte[])reader["Data"]); 
      } 
     } 
    } 
} 

コードは少しそれをより簡潔にするために修正されたが、私は主に、いくつかの検証とログを削除しました。

アプリケーションの実行中にMySql Workbenchでサーバーを監視すると、約2分後に100%に達するか、1000個のイメージが選択されるまで、「InnoDBバッファ使用率」がゆっくりと上昇します。私が読んだことではこれは完全に正常ですが、InnoDBバッファが100%に近づくまで、画像は遅く、遅くなります。

タイムアウトが切れています。操作が完了する前にタイムアウト時間が経過したか、サーバーが応答していません。

データベースサーバー情報:

  • MySQLサーバ5.6
  • すべてのテーブルはInnoDBの
  • 8ギガバイトのRAM
とWindowsサーバー2012上で実行
  • innodb_buffer_pool_size = 1ギガバイト
  • を使用しています

    写真のテーブルの定義:

    CREATE TABLE `Photos` (
        `Id` int(11) NOT NULL AUTO_INCREMENT, 
        `PersonId` int(11) NOT NULL, 
        `Data` longblob NOT NULL, 
        PRIMARY KEY (`Id`), 
        KEY `FK_PersonId_IDX` (`photo_person_id`), 
        CONSTRAINT `FK_PersonId` FOREIGN KEY (`PersonId`) REFERENCES `Persons` (`Id`) 
          ON DELETE CASCADE ON UPDATE CASCADE 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
    

    アプリのメモリ使用量は非常に少ないです。 innodb_buffer_pool_sizeを大きくすると、問題が発生するまでの時間(またはエクスポートされた写真の数)がサイズの増加に比例して増えますが、これらのイメージを書き出すためにサーバにメモリを追加する必要はありません。

    InnoDBバッファプールを大規模なBLOBで満たすのはこの問題の原因ですが、これらのBLOBをすべて選択したい場合、実際にはこれを防ぐ方法はありません私に何ができる?おそらくタイムアウトを増やすことはできますが、それは明白な理由による悪い解決策に過ぎません。PhotosテーブルをMyISAMに変更して問題を解決することを検討しましたが、他に簡単な解決方法がある場合は、 。私は、実際にこの問題を回避する方法が他にない場合は、写真をエクスポートするための完全な代替ソリューションにもオープンしています。

    私は実際に他の情報が関連しているかどうかわかりませんので、他の詳細についてはコメントにお尋ねください。

  • +0

    コードはどこにありますか?あなたは*接続*を閉じますか?コマンドまたはリーダーを廃棄しても、サーバー側のリソースは解放されません。*ページングは​​必要ありません - レコードを一度に1つずつ読み込んでディスクに書き込むだけです。 –

    +0

    関連するコードを追加しましたが、私はページングを必要としないという意味ですか?私は一度にすべての写真を選択するだけではできません...また、私はすべてのクエリ間の接続を閉じるために私には不思議そうですが、私はそれを試すことができると思います... – moggizx

    +0

    最初のfor-ループは何の違いもありませんでした。 – moggizx

    答えて

    1

    OFFSETを使用しないでください。本当に必要な10に到達するには、すべての行をステップ実行する必要があります。また、行が追加/削除されている場合、行を見落としたり複製したりする可能性があります。

    代わりremember where you left off

    場合は、あなただけの10のIDSではなく、残りの列をフェッチ前記「怠惰はeval」を使用し、その後、実装することはできませんいくつかの理由のために。これはサブクエリにあります。次にJOINを表に戻して残りの希望の列を取得します。

    +0

    ありがとう、これで解決しました! – moggizx

    関連する問題