了解 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,想知道具体实现的可以自己下载阅读代码试试
在测试一堆值时,我总是很容易地使用 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,想知道具体实现的可以自己下载阅读代码试试