perl – 何时(SELECT)查询计划?
在PostgreSQL中,什么时候(SELECT)查询计划?
是吗: >在声明准备时间,或 我问的原因是存在Stackoverflow问题:same query,two different ways,vastly different performance 很多人似乎认为查询的计划方式不同,因为在一种情况下,查询包含字符串文字(‘foo’),在另一种情况下,它是一个占位符(?). 现在我的想法是,这是一个红色的鲱鱼,因为查询不是在语句准备时计划的,而是实际计划在SELECT时间. 因此,比如说,我可以使用占位符准备一个语句,然后使用不同的绑定值多次运行查询,并为每个不同的绑定值运行查询计划程序. 我怀疑question linked above归结为该值的PostgreSQL数据类型,在’foo’文字的情况下,已知它是一个字符串,但在占位符的情况下,该类型不能被判断,所以正在查询计划程序作为一些奇怪的类型,它无法创建一个有效的计划.在这种情况下,问题不在于查询的计划方式不同,因为该值本身就是占位符(在语句准备时),但该值是以不同的PostgreSQL类型传递给查询的,这就是影响查询计划器.要解决这个问题,只需将占位符与适当的显式类型声明绑定即可. 解决方法
我不能谈论客户端的Perl接口本身,但我可以对PostgreSQL服务器端有所了解.
PostgreSQL准备了陈述和毫无准备的陈述.毫无准备的语句会立即被解析,计划和执行.它们也不支持参数替换.在普通的psql shell上,您可以像这样显示他们的查询计划: tmpdb> explain select * from sometable where flag = true; 另一方面,有准备好的陈述:它们通常(参见下面的“例外”)在一个步骤中解析和计划,并在第二步中执行.它们可以使用不同的参数重新执行几次,因为它们确实支持参数替换. psql中的等价物如下: tmpdb> prepare foo as select * from sometable where flag = $1; tmpdb> explain execute foo(true); 您可能会看到,该计划与未准备好的声明中的计划不同,因为计划确实已经在准备阶段进行,如PREPARE的文档中所述:
这也意味着,该计划未针对替换参数进行优化:在第一个示例中可能使用标记索引,因为PostgreSQL知道在一百万个条目中只有十个具有值true.当PostgreSQL使用预准备语句时,这种推理是不可能的.在这种情况下,会创建一个计划,该计划将尽可能好地适用于所有可能的参数值.这可能会排除提到的索引,因为通过随机访问(由于索引)获取整个表的更好部分比普通顺序扫描慢. PREPARE doc证实了这一点:
BTW – 关于计划缓存,PREPARE doc也有话要说:
此外,没有自动计划缓存,也没有多个连接的缓存/重用. 例外:我已经提到“通常”.显示的psql示例不是Perl DBI真正使用的客户端适配器.它使用某个protocol.这里术语“简单查询”对应于psql中的“未准备查询”,术语“extended query”对应于“准备好的查询”,但有一个例外:(一个)“未命名语句”之间存在区别和(可能是多个)“命名陈述”.关于命名陈述,doc说:
并且:
所以在这种情况下,计划是在没有参数的情况下完成的,如上所述的PREPARE – 没有什 提到的例外是“未命名的声明”.医生说:
这是好处:虽然未命名的语句是“准备好的”(即可以有参数替换),但它也可以使查询计划适应实际参数. BTW:在过去的PostgreSQL服务器版本中,未命名语句的确切处理已经多次改变.如果您真的想要,可以查找旧文档以获取详细信息. 理由 – Perl /任何客户: 像Perl这样的客户端如何使用协议是一个完全不同的问题.一些客户端像Java的JDBC驱动程序基本上说:即使程序员使用预准备语句,前五个(或左右)执行内部映射到“简单查询”(即实际上没有准备),之后驱动程序切换到“命名陈述“. 所以客户有这些选择: >每次使用“简单查询”协议强制(重新)规划. Perl目前做了什么:我不知道.但提到的“红鲱鱼”并非不太可能. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |