了解 SQL 中的元组语法

Understanding tuple syntax in SQL

在测试一堆值时,我总是很容易地使用 IN (val1, val2, ...) 语法。但是,我想知道它实际评估的是什么类型的数据结构,这是一个 table 函数吗?例如:

-- to populate data
CREATE TABLE main_territory (
  name varchar NOT NULL,
  is_fake_territory integer NOT NULL,
  code varchar NOT NULL
);

INSERT INTO main_territory (name, is_fake_territory, code) VALUES ('Afghanistan', 0, 'AF'), ('Albania', 0, 'AL'), ('Algeria', 0, 'DZ');
select '1' as "query#", * from main_territory where code in ('AF', 'AL') union all
select '2' as "query#", * from main_territory where code in (select 'AF' UNION ALL select 'AL') UNION ALL
select '3' as "query#", * from main_territory where code in (select code from main_territory where name ='Albania' or name = 'Afghanistan')

第二个和第三个查询 return 单列 table(这称为标量 -table 吗?),所以我想 (expr1, expr2, ...)做同样的事情 - 它评估为单列 table。准确吗,或者这是什么实际数据类型?

混淆是可以理解的,因为它们实际上是两种不同的 IN:

WHERE expr IN (2, 3, 4, ...)
WHERE expr IN (SELECT ...)

第一个会被转换成这样的数组:

                    QUERY PLAN                  
═══════════════════════════════════════════════════
 Seq Scan on tab
   Filter: (expr = ANY ('{2,3,4,...}'::integer[]))

或者,如果列表只有一个元素,

      QUERY PLAN     
══════════════════════
 Seq Scan on tab
   Filter: (expr = 2)

第二个将作为连接执行,例如:

            QUERY PLAN             
═══════════════════════════════════
 Hash Join
   Hash Cond: (tab.expr = sub.col)
   ->  Seq Scan on tab
   ->  Hash
         ->  Seq Scan on sub

所以,回答你的问题:一个普通的 IN 列表将被转换为一个数组,并且 IN 变成 = ANY

我不会调用 IN ( ) 谓词元组比较。元组比较(也称为行构造函数比较)的示例是:

WHERE (col1, col2) = ('abc', 123)

或者您甚至可以进行多值行构造函数比较:

WHERE (col1, col2) IN (('abc', 123), ('xyz', 456))

您显示的示例只是 IN ( ) 谓词,它将单个值与值列表进行比较。如果该值与列表中的任何值匹配,则谓词得到满足。该列表可以是表达式或文字的固定列表:

WHERE code IN ('AF', 'AL') 

或者它可以是子查询的结果:

WHERE code IN (SELECT code FROM ...)

具体如何实现取决于各个 RDBMS 的代码。它可能必须具体化子查询的结果并将其存储为内部列表。在某些软件中,它们可能会使用一个临时的 table 一列作为数据结构来存储子查询的结果。然后 IN ( ) 谓词可以作为针对临时 table 的连接执行。如果说 SQL 引擎应该能够高效地完成一件事,那就是连接。 :-)

但是如果子查询的结果是数百万行,这可能会很昂贵。在那种情况下,聪明的优化器会“分解”出 IN ( ) 谓词并只进行连接。也就是说,它将读取 code 的每个值并在第二个 table 的 code 列中进行索引查找。这意味着本身没有数据结构,它只是对连接的评估。

真正的答案是 implementation-dependent。 MySQL和PostgreSQL都是open-source,想知道具体实现的可以自己下载阅读代码试试