プロファイルの写真をデータベースに保存し、これらの写真をどこかのディスクにエクスポートする小さな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
写真のテーブルの定義:
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に変更して問題を解決することを検討しましたが、他に簡単な解決方法がある場合は、 。私は、実際にこの問題を回避する方法が他にない場合は、写真をエクスポートするための完全な代替ソリューションにもオープンしています。
私は実際に他の情報が関連しているかどうかわかりませんので、他の詳細についてはコメントにお尋ねください。
コードはどこにありますか?あなたは*接続*を閉じますか?コマンドまたはリーダーを廃棄しても、サーバー側のリソースは解放されません。*ページングは必要ありません - レコードを一度に1つずつ読み込んでディスクに書き込むだけです。 –
関連するコードを追加しましたが、私はページングを必要としないという意味ですか?私は一度にすべての写真を選択するだけではできません...また、私はすべてのクエリ間の接続を閉じるために私には不思議そうですが、私はそれを試すことができると思います... – moggizx
最初のfor-ループは何の違いもありませんでした。 – moggizx