私たちは皆、次のスタイルでベースを操作することに慣れています。
- リクエストを満たす
- 答えを待つ
- 実行を続ける
しかし、長いリクエストが機能している間、アプリケーションで何か役に立つことができます。 CPU時間はアイドル状態にしないでください。
PostgreSQLの場合、DBD :: Pgには非同期性があります。 そして時々それは私たちを助けます。
要求が完了するのを待たずに、アプリケーションの実行を継続できます。 これは準備要求のpg_asyncパラメータに含まれています。
use strict;
use warnings;
use Time::HiRes 'sleep';
use DBD::Pg ':async';
my $dbh = DBI->connect('dbi:Pg:dbname=postgres', 'postgres', '', {AutoCommit=>0,RaiseError=>1});
##
my $sth = $dbh->prepare("SELECT pg_sleep(?)", {pg_async => PG_ASYNC});
$sth->execute(5);
## , -
print "Your query is processing. Thanks for waiting\n";
check_on_the_kids();
while (!$dbh->pg_ready) {
check_on_the_kids();
## -
sleep 0.1;
}
print "The query has finished. Gathering results\n";
my $result = $sth->pg_result;
print "Result: $result\n";
my $info = $sth->fetchall_arrayref();
pg_asyncには3つの定数があります。
- PG_ASYNC-非同期モードでのリクエストの実行
- PG_OLDQUERY_CANCEL-その時点で以前のリクエストが機能していた場合、キャンセルされます
- PG_OLDQUERY_WAIT-前のリクエストを待機してから、新しいリクエストの実行を開始するブロック
また、3つのヘルパーメソッドがあります-
- pg_cancel-リクエストをキャンセルします。 実際にもう1つの接続が開き、SELECTが送信されますpg_cancel_backend(?);
- pg_ready-リクエストが完了するとtrueを返します。
- pg_result-要求が実行されるまでブロックされます。その後、標準モードで-> executeと同じ結果が返されます。
マイナスの点-リクエストの実行時にコールバックを設定することはできません。 常に確認する必要があります。
また、1つの接続で一度に実行できる要求は1つだけです。 しかし、何十もの接続を開いてそれらに順番にリクエストを送信することを妨げるものは何ですか?)
このテクノロジーのアプリケーションについてお話します。
- 重いクエリ+複雑なロジック。 サーバーとデータベースサーバーを均等にロードします。
while(){
my $ foo = compute_foo();#重い関数
#前のリクエストが実行されるまでブロック
$ dbh-> do( 'UPDATE stats SET foo =?'、{pg_async => PG_ASYNC + PG_OLDQUERY_WAIT}、$ foo);
}
- 複数のデータベースサーバーで動作する
$ first_dbh-> do( 'DELETE FROM old_data'、{pg_async => PG_ASYNC});
$ second_dbh-> do( 'UPDATE new_data SET status = 0'、{pg_async => PG_ASYNC})
- タイムアウト。 まだ完了していない場合は、タイムアウトでリクエストを強制終了できます
- 競争力のある問い合わせ。 同じリクエストを2つのサーバーに送信し、より速く応答したサーバーからデータを送信します。
- 結果にまったく関心がないクエリ