可用版本:Dev (3.21) | 最新 (3.20) | 3.19 | 3.18 | 3.17 | 3.16 | 3.15 | 3.14 | 3.13 | 3.12 | 3.11

IN列表填充

适用于 ✅ 开源版   ✅ 专业版   ✅ 企业版

具有游标缓存/语句缓存的数据库(例如 Oracle、SQL Server、DB2 等)针对预处理语句的重用进行了高度优化。当客户端向服务器发送预处理语句时,服务器将转到缓存并查找是否已经存在先前计算的语句的执行计划(即 SQL 字符串)。这称为“软解析”(在 Oracle 中)。如果不存在,则即时计算执行计划。这称为“硬解析”(在 Oracle 中)。

在高吞吐量 OLTP 系统中,防止硬解析非常重要,因为在这些系统中,查询通常不是很复杂,但在短时间内会运行数百万次。使用绑定变量,这通常不是问题,但 IN 谓词除外,即使在使用绑定变量时,它也会生成不同的 SQL 字符串

-- All of these are different SQL statements:
SELECT * FROM AUTHOR WHERE ID IN (?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?)

Java / jOOQ 开发人员可能不清楚这个问题,因为它们总是从同一个 jOOQ 语句生成

// All of these are the same jOOQ statement
DSL.using(configuration)
   .select()
   .from(AUTHOR)
   .where(AUTHOR.ID.in(collection))
   .fetch();

根据集合的可能大小,可能值得探索使用数组或临时表作为解决方法,或者重用首先生成 ID 集的原始查询(通过半连接)。但有时,这是不可能的。在这种情况下,用户可以选择第三种解决方法:启用 inListPadding 设置。如果启用,jOOQ 会将 IN 列表“填充”到长度为 2 的幂(可以使用 Settings.inListPadBase 配置)。因此,原始查询将如下所示

-- Original
SELECT * FROM AUTHOR WHERE ID IN (?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?)
-- Padded
SELECT * FROM AUTHOR WHERE ID IN (?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?, ?, ?)
SELECT * FROM AUTHOR WHERE ID IN (?, ?, ?, ?, ?, ?, ?, ?)

这种技术将大大减少可能的 SQL 字符串的数量,而不会过多地影响 IN 列表较小的情况。在填充时,最后一个绑定变量将被简单地重复多次。

通常,有一种更好的方法 - 将此作为最后的手段!

示例配置

Settings settings = new Settings()
    .withInListPadding(true) // Default to false
    .withInListPadBase(4);   // Default to 2

反馈

您对此页面有任何反馈吗? 我们很乐意听取您的意见!

The jOOQ Logo