我运行了一个Drupal 7.2网站,嵌入了a flash game和一些用于播放器统计的自定义PHP脚本。使用CentOS 5.6/64位,PostgreSQL 8.4.8和PHP 5.3。它是一个具有4GB RAM的Quad-Opteron。
在高峰期(大约有500名玩家在线),我的网站曾经因为太多的postmaster进程而崩溃。在pgsql-general mailing list的建议下,我安装了pgbouncer 1.3.4,并安装了以下/etc/pgbouncer.ini:
[databases]
pref = host=/tmp user=pref password=XXX dbname=pref
[pgbouncer]
logfile = /var/log/pgbouncer.log
pidfile = /var/run/pgbouncer/pgbouncer.pid
listen_port = 6432
unix_socket_dir = /tmp
auth_type = md5
auth_file = /var/lib/pgsql/data/global/pg_auth
pool_mode = transaction
;pool_mode = session
server_check_delay = 10
max_client_conn = 200
default_pool_size = 16
log_connections = 0
log_disconnections = 0
log_pooler_errors = 1
字符串
并在postgresql. conf中增加了shared_buffers = 1024 MB,减少了max_connections = 50。
这很有帮助,但我经常遇到一个问题,即无法找到准备好的PDO语句:
SQLSTATE[26000]: Invalid sql statement name: 7 ERROR: prepared statement "pdo_stmt_00000016" does not exist
型
- 可能是因为pgbouncer在prepare()和execute()之间切换连接。
我无法将pgbouncer切换到会话模式-我的网站将挂起。
我尝试添加PDO::ATTR_EMULATE_PREPARES => true-我的网站也挂起了。
我已经在每个prepare()和execute()调用周围添加了transaction()和commit()-但是我经常得到以下错误:
SQLSTATE[25P02]: In failed sql transaction: 7 ERROR: current transaction is aborted, commands ignored until end of transaction block
型
下面是我的代码的一个摘录失败的错误-它是非常简单的,只是调用五个SELECT语句:
function fetch_top() {
$table = '';
$top = '';
try {
# throw exception on any errors
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
$db = new PDO(sprintf('pgsql:host=%s port=%u; dbname=%s',
DBHOST, DBPORT, DBNAME), DBUSER, DBPASS, $options);
# last week's winner
$db->beginTransaction();
$sth = $db->prepare("
select u.id,
u.first_name,
u.avatar,
u.female,
u.city,
m.money,
u.login > u.logout as online
from pref_users u, pref_money m where
m.yw=to_char(current_timestamp - interval '1 week', 'IYYY-IW') and
u.id=m.id
order by m.money desc
limit 1
");
$sth->execute();
$winner = $sth->fetch(PDO::FETCH_OBJ);
$db->commit();
$db->beginTransaction();
$sth = $db->prepare('
select count(id) from (
select id,
row_number() over(partition by yw order by money desc) as ranking
from pref_money
) x
where x.ranking = 1 and id=?
');
$sth->execute(array($winner->id));
$winner_medals = $sth->fetchColumn();
$db->commit();
# current week leader
$db->beginTransaction();
$sth = $db->prepare("
select u.id,
u.first_name,
u.avatar,
u.female,
u.city,
m.money,
u.login > u.logout as online
from pref_users u, pref_money m where
m.yw=to_char(current_timestamp, 'IYYY-IW') and
u.id=m.id
order by m.money desc
limit 1
");
$sth->execute();
$leader = $sth->fetch(PDO::FETCH_OBJ);
$db->commit();
$db->beginTransaction();
$sth = $db->prepare('
select count(id) from (
select id,
row_number() over(partition by yw order by money desc) as ranking
from pref_money
) x
where x.ranking = 1 and id=?
');
$sth->execute(array($leader->id));
$leader_medals = $sth->fetchColumn();
$db->commit();
# fetch top players
$db->beginTransaction();
$sth = $db->prepare("
select u.id,
u.first_name,
u.female,
u.city,
m.money,
u.login > u.logout as online
from pref_users u, pref_money m where
m.yw=to_char(current_timestamp, 'IYYY-IW') and
u.id=m.id
order by m.money desc
limit 7
");
$sth->execute();
$i = 0;
while ($player = $sth->fetch(PDO::FETCH_OBJ)) {
$top .= user_link($player) . ($i++ > 0 ? '' : ' »') . '<br />';
}
$db->commit();
# create the HTML table
$table = sprintf('.... skipped for brevity ....');
} catch (Exception $e) {
exit('Database problem: ' . $e->getMessage());
}
return $table;
}
型
有没有人帮忙?亚历克斯
3条答案
按热度按时间qc6wkl3g1#
我不使用PDO,但在会话模式下使用pgBouncer的预处理语句对我来说确实有效。我只需要设置“server_reset_query = DISCARD ALL”,预处理语句就可以正常工作。你可以设置pool_mode为会话,并设置上述变量吗?
o2rvlv0m2#
交易池
要使准备好的语句在这种模式下工作,需要PgBouncer在内部跟踪它们,而PgBouncer没有这样做。因此,在这种模式下继续使用PgBouncer的唯一方法是完全禁用准备好的语句。
mrfwxfqh3#
1.配置
pgbouncer
以使用transaction pooling
1.编写一个PL函数来创建
PREPARE
艾德语句1.让您的PL函数检查
pg_prepared_statements
系统视图,并生成所有准备好的语句(如果缺少)。1.将SQL命令执行更改为:
BEGIN
个SELECT create_prepared_statements();
个/* Do whatever it is that you would normally do */
个COMMIT
个之所以需要调用这个尚未编写的
create_prepared_statements()
PL函数,是因为您不知道您的连接被调度到哪个后端,或者您正在与之交谈的后端是否是新生成的,并且没有PREPARE
ed语句。根据您如何使用
PREPARE
的艾德语句,查看VIEW
或PL函数,因为它们会自动生成和缓存PREPARE
的艾德语句。我建议更积极地使用PL/pgsql函数,因为这是最容易维护的方法。