自动批处理模式只对postgresql 14+版本的客户端库有效,其他情况下会被忽略,讲自动批处理之前,先了解一下pipeline模式。
pipeline模式
从postgresql 14之后,它的客户端库提供了pipelining模式接口,在pipelining模式下,新sql请求可以直接发送到服务端而不必等到上一个请求的结果返回(这和HTTP的pipelining的概念一致),详情请参考Pipeline mode。该模式对性能有很大的帮助,可以使较少的数据库连接就支持较大的并发请求。 drogon在1.7.6版本之后开始支持,drogon会自动检查libpq是否支持pipeline模式,如果支持的话,通过drogon的DbClient发送的所有请求都是在pipeline模式下的。
自动批处理
默认情况下,非事务客户端,drogon为每个sql请求创建同步点,即每个单独的sql语句都是一个隐式事务,这可以保证sql请求之间相互独立,这使得pipeline模式和非pipeline模式在用户看来是完全等价的。
不过,每条sql语句创建一个同步点也有比较大的性能开销,因此drogon提供了一种自动批处理模式,在该模式下,同步点的创建不再是每条sql之后都创建一个,而是若干sql语句之后创建,同一个链接创建同步点的规则如下:
- 一个EventLoop循环之内的最后一条sql之后必然创建同步点;
- 一个写数据库的sql之后创建同步点;
- 一个长sql之后创建同步点;
- 上一个同步点之后连续的sql语句数量达到上限的时候创建同步点;
注意,同一链接内两个同步点之间的sql相当于属于同一个隐式事务,drogon没有提供显式的开启和关闭同步点的接口,所以这些sql在逻辑上可能互不相关,由于它们处于同一个事务中,它们也会相互干扰,因此,该模式并不是完全安全的模式,它有如下问题:
- 一个失败的sql会导致它之前的到上一个同步点之后的sql语句都发生回滚,但用户并不会收到相关通知,因为没有使用显式事务;
- 一个失败的sql会导致它之后的到下一个同步点之前的sql语句都返回失败;
- 写数据库的sql判别是靠简单的关键字匹配(insert,update等关键字),这并不能涵盖所有的情况,比如通过select调用了存储过程的情况,因此虽然drogon努力减少自动批处理的负面影响,但它不是绝对安全的;
所以,自动批处理模式对性能提高有一定帮助,但它并不安全,由用户自己决定在什么情况下使用它,比如纯只读的sql使用自动批处理模式的DbClient。
注意 即使是只读的sql有时候依然会引起事务失败(比如select超时),因此它后续的sql也会受它影响而失败(这对用户来说是可能是不可接受的,因为在应用逻辑上它们可能互不相关),所以,严格来说,自动批处理模式的应用场景应限制在只读且非关键的数据查询上。建议用户创建单独的自动批处理DbClient供这种sql使用。当然,容易想到,由自动批处理模式的DbClient生成的事务对象是可以放心使用的。
自动批处理的使能
当使用newPgClient接口创建客户端时,把第三个参数设为true即可使能自动批处理模式; 当使用配置文件创建客户端时,把auto_batch选项设为true即可使能该客户端的自动批处理模式;