Article
查询队列演示:把 pg 的并发警告画成时间线
同一个 PostgreSQL client 上同时发出多个查询时,真正需要理解的是连接、队列与并发之间的关系。
开发服务器曾经出现过一条 pg 弃用警告:当一个 client 还在执行查询时,又调用了 client.query()。在 pg 8 中它仍然会排队执行,但 pg 9 不再鼓励依赖这种隐式行为。
单看 warning 很容易误解成“不能并发查询”。问题其实更具体:一个 PostgreSQL client 在同一时刻只能处理一条查询。 真正的并行需要多个连接,或者由连接池分配多个 client。
查询队列演示没有真的向数据库发送请求,而是把三种执行方式建模成时间线数据:顺序 await、连接池并行、单 client 排队。每条 query 只需要记录开始位置、持续长度和是否处于等待状态。
interface QueryBar {
id: string
start: number
duration: number
queued: boolean
color: string
}
function queryStyle(query: QueryBar) {
return {
left: `${query.start}%`,
width: `${query.duration}%`,
backgroundColor: query.color
}
}
顺序模式最容易推理,尤其适合共享事务上下文的操作。前一个查询完成后再执行下一个,不会出现 client 正忙的问题。
const posts = await client.query(postsSql)
const comments = await client.query(commentsSql)
如果查询彼此独立,并且确实需要缩短总耗时,可以让 pool 为它们分配连接。表面上仍然是 Promise.all,但并行能力来自连接池,而不是同一个 client 突然能同时处理多条 SQL。
const [posts, comments] = await Promise.all([
pool.query(postsSql),
pool.query(commentsSql)
])
最值得警惕的是拿到一个 client 后直接并行调用多次 client.query()。它过去可能“能跑”,却把执行顺序交给了隐式队列。warning 的意义正是提醒我们:应该把控制流写清楚。
这个实验把抽象的连接模型变成了可移动的条形图。切换模式时,查询是在同一条轨道上依次前进,还是在多个 client 上同时开始,一眼就能看出来。
可以在 查询队列演示 重放三种时间线。
Comments
留言
需要 GitHub 登录。新评论会先进入待审核,别急,它只是先坐到门口等一会儿。
使用 GitHub 登录后可以评论。
已通过评论
0还没有通过审核的评论。桌子很安静,第一杯茶还没端上来。