diff --git a/pkg/sql/logictest/testdata/logic_test/apply_join b/pkg/sql/logictest/testdata/logic_test/apply_join index 21f9d9c26f7e..8f196f12980e 100644 --- a/pkg/sql/logictest/testdata/logic_test/apply_join +++ b/pkg/sql/logictest/testdata/logic_test/apply_join @@ -467,7 +467,7 @@ VALUES FROM (VALUES (tab_54747.col_95055)) AS tab_54752 (col_95061) WHERE - (SELECT 0) < tab_54752.col_95061 + (SELECT random()::INT) < tab_54752.col_95061 ) FROM (VALUES (0:::OID), (3790322641:::OID)) AS tab_54747 (col_95055) diff --git a/pkg/sql/opt/exec/execbuilder/testdata/subquery b/pkg/sql/opt/exec/execbuilder/testdata/subquery index 05bf469c2493..9b629e182b63 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/subquery +++ b/pkg/sql/opt/exec/execbuilder/testdata/subquery @@ -4,7 +4,7 @@ # Uncorrelated subqueries. # ------------------------------------------------------------------------------ statement ok -CREATE TABLE abc (a INT PRIMARY KEY, b INT, c INT); +CREATE TABLE abc (a INT PRIMARY KEY, b INT, c INT, FAMILY (a, b, c)); CREATE TABLE abc2 (a INT PRIMARY KEY, b INT, c INT) query T @@ -13,22 +13,12 @@ EXPLAIN ALTER TABLE abc SPLIT AT VALUES ((SELECT 42)) distribution: local vectorized: true · -• root -│ -├── • split -│ │ index: abc@abc_pkey -│ │ expiry: CAST(NULL AS STRING) -│ │ -│ └── • values -│ size: 1 column, 1 row +• split +│ index: abc@abc_pkey +│ expiry: CAST(NULL AS STRING) │ -└── • subquery - │ id: @S1 - │ original sql: (SELECT 42) - │ exec mode: one row - │ - └── • values - size: 1 column, 1 row +└── • values + size: 1 column, 1 row statement ok ALTER TABLE abc SPLIT AT VALUES ((SELECT 1)) @@ -39,23 +29,13 @@ EXPLAIN ALTER RANGE RELOCATE FROM 11 TO 22 FOR VALUES ((SELECT 1)) distribution: local vectorized: true · -• root -│ -├── • relocate range -│ │ replicas: VOTERS -│ │ to: 22 -│ │ from: 11 -│ │ -│ └── • values -│ size: 1 column, 1 row +• relocate range +│ replicas: VOTERS +│ to: 22 +│ from: 11 │ -└── • subquery - │ id: @S1 - │ original sql: (SELECT 1) - │ exec mode: one row - │ - └── • values - size: 1 column, 1 row +└── • values + size: 1 column, 1 row query T EXPLAIN ALTER RANGE 22 RELOCATE FROM ((SELECT 1)) TO ((SELECT 2)) @@ -63,31 +43,13 @@ EXPLAIN ALTER RANGE 22 RELOCATE FROM ((SELECT 1)) TO ((SELECT 2)) distribution: local vectorized: true · -• root -│ -├── • relocate range -│ │ replicas: VOTERS -│ │ to: @S1 -│ │ from: @S2 -│ │ -│ └── • values -│ size: 1 column, 1 row -│ -├── • subquery -│ │ id: @S1 -│ │ original sql: ((SELECT 2)) -│ │ exec mode: one row -│ │ -│ └── • values -│ size: 1 column, 1 row +• relocate range +│ replicas: VOTERS +│ to: 2 +│ from: 1 │ -└── • subquery - │ id: @S2 - │ original sql: ((SELECT 1)) - │ exec mode: one row - │ - └── • values - size: 1 column, 1 row +└── • values + size: 1 column, 1 row query T EXPLAIN SELECT EXISTS (SELECT a FROM abc) @@ -228,7 +190,7 @@ vectorized: true # the subquery's plan must be visible in EXPLAIN query T -EXPLAIN VALUES (1), ((SELECT 2)) +EXPLAIN VALUES (1), ((SELECT random()::INT)) ---- distribution: local vectorized: true @@ -240,7 +202,7 @@ vectorized: true │ └── • subquery │ id: @S1 - │ original sql: (SELECT 2) + │ original sql: (SELECT random()::INT8) │ exec mode: one row │ └── • values @@ -291,6 +253,33 @@ vectorized: true table: tab4@tab4_pkey spans: FULL SCAN +# Subqueries with single, constant values can be inlined for index-acceleration. +query T +EXPLAIN (VERBOSE) +SELECT * FROM abc WHERE a = (SELECT 1) +---- +distribution: local +vectorized: true +· +• scan + columns: (a, b, c) + estimated row count: 1 (missing stats) + table: abc@abc_pkey + spans: /1/0 + +query T +EXPLAIN (VERBOSE) +SELECT * FROM abc WHERE a >= (SELECT 1) +---- +distribution: local +vectorized: true +· +• scan + columns: (a, b, c) + estimated row count: 333 (missing stats) + table: abc@abc_pkey + spans: /1- + # ------------------------------------------------------------------------------ # Correlated subqueries. # ------------------------------------------------------------------------------ diff --git a/pkg/sql/opt/exec/execbuilder/testdata/udf b/pkg/sql/opt/exec/execbuilder/testdata/udf index 318db482c3c4..d806baa33b85 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/udf +++ b/pkg/sql/opt/exec/execbuilder/testdata/udf @@ -9,7 +9,7 @@ CREATE TABLE t ( INSERT INTO t VALUES (1, 1), (2, 2), (3, 3), (4, 1), (5, 1); statement ok -CREATE FUNCTION one() RETURNS INT LANGUAGE SQL AS 'SELECT 1'; +CREATE FUNCTION one() RETURNS INT IMMUTABLE LANGUAGE SQL AS 'SELECT 1'; query T EXPLAIN SELECT one() @@ -27,7 +27,7 @@ distribution: local vectorized: true · • filter -│ filter: a = one() +│ filter: a = 1 │ └── • scan missing stats @@ -259,6 +259,51 @@ vectorized: true └── • emptyrow columns: () +# Immutable UDFs can be inlined for index-acceleration. +query T +EXPLAIN (VERBOSE) +SELECT * FROM t WHERE k = one() +---- +distribution: local +vectorized: true +· +• scan + columns: (k, a) + estimated row count: 1 (missing stats) + table: t@t_pkey + spans: /1/0 + +statement ok +CREATE FUNCTION num(n INT) RETURNS INT IMMUTABLE LANGUAGE SQL AS $$ + SELECT n +$$ + +query T +EXPLAIN (VERBOSE) +SELECT * FROM t WHERE k = num(2) +---- +distribution: local +vectorized: true +· +• scan + columns: (k, a) + estimated row count: 1 (missing stats) + table: t@t_pkey + spans: /2/0 + +query T +EXPLAIN (VERBOSE) +SELECT * FROM t WHERE k >= num(2) +---- +distribution: local +vectorized: true +· +• scan + columns: (k, a) + estimated row count: 333 (missing stats) + table: t@t_pkey + spans: /2- + subtest regressions diff --git a/pkg/sql/opt/norm/rules/scalar.opt b/pkg/sql/opt/norm/rules/scalar.opt index 0ee1943db443..e48e84d24848 100644 --- a/pkg/sql/opt/norm/rules/scalar.opt +++ b/pkg/sql/opt/norm/rules/scalar.opt @@ -299,6 +299,14 @@ $input => (Exists $input $subqueryPrivate) +# EliminateConstValuesSubquery replaces a subquery with a constant value if the +# subquery's input is a single-row, single-column Values expression with a +# constant value. +[EliminateConstValueSubquery, Normalize] +(Subquery (Values [ (Tuple [ $value:(Const) ]) ])) +=> +$value + # SimplifyCaseWhenConstValue removes branches known to not match. Any # branch known to match is used as the ELSE and further WHEN conditions # are skipped. If all WHEN conditions have been removed, the ELSE diff --git a/pkg/sql/opt/norm/testdata/rules/inline b/pkg/sql/opt/norm/testdata/rules/inline index f6d63a234096..036e40639d26 100644 --- a/pkg/sql/opt/norm/testdata/rules/inline +++ b/pkg/sql/opt/norm/testdata/rules/inline @@ -1251,21 +1251,16 @@ norm expect=InlineUDF SELECT one_strict() FROM (VALUES (1), (2), (3)) v(i) ---- project - ├── columns: one_strict:3 + ├── columns: one_strict:3!null ├── cardinality: [3 - 3] + ├── fd: ()-->(3) ├── values │ ├── cardinality: [3 - 3] │ ├── () │ ├── () │ └── () └── projections - └── subquery [as=one_strict:3, subquery] - └── values - ├── columns: "?column?":2!null - ├── cardinality: [1 - 1] - ├── key: () - ├── fd: ()-->(2) - └── (1,) + └── 1 [as=one_strict:3] # A UDF is not inlined when the arguments are not constants or either Variable # or Const expressions. diff --git a/pkg/sql/opt/norm/testdata/rules/subquery b/pkg/sql/opt/norm/testdata/rules/subquery new file mode 100644 index 000000000000..f9ce77423c68 --- /dev/null +++ b/pkg/sql/opt/norm/testdata/rules/subquery @@ -0,0 +1,105 @@ +exec-ddl +CREATE TABLE t ( + a INT, + b INT +) +---- + +# -------------------------------------------------- +# EliminateConstValueSubquery +# -------------------------------------------------- + +norm expect=EliminateConstValueSubquery +SELECT (SELECT 1) +---- +values + ├── columns: "?column?":2!null + ├── cardinality: [1 - 1] + ├── key: () + ├── fd: ()-->(2) + └── (1,) + +norm expect=EliminateConstValueSubquery +SELECT * FROM t WHERE a = (SELECT 1) +---- +select + ├── columns: a:1!null b:2 + ├── fd: ()-->(1) + ├── scan t + │ └── columns: a:1 b:2 + └── filters + └── a:1 = 1 [outer=(1), constraints=(/1: [/1 - /1]; tight), fd=()-->(1)] + +norm expect=EliminateConstValueSubquery +SELECT * FROM t WHERE a >= (SELECT 1) +---- +select + ├── columns: a:1!null b:2 + ├── scan t + │ └── columns: a:1 b:2 + └── filters + └── a:1 >= 1 [outer=(1), constraints=(/1: [/1 - ]; tight)] + +# Cannot eliminate multi-row values subquery. +norm expect-not=EliminateConstValueSubquery +SELECT (VALUES (1), (2)) +---- +values + ├── columns: column1:2 + ├── cardinality: [1 - 1] + ├── key: () + ├── fd: ()-->(2) + └── tuple + └── subquery + └── max1-row + ├── columns: column1:1!null + ├── error: "more than one row returned by a subquery used as an expression" + ├── cardinality: [1 - 1] + ├── key: () + ├── fd: ()-->(1) + └── values + ├── columns: column1:1!null + ├── cardinality: [2 - 2] + ├── (1,) + └── (2,) + +# Cannot eliminate multi-column values subquery. +norm expect-not=EliminateConstValueSubquery +SELECT (1, 2) = (SELECT 1, 2) +---- +values + ├── columns: "?column?":4 + ├── cardinality: [1 - 1] + ├── immutable + ├── key: () + ├── fd: ()-->(4) + └── tuple + └── eq + ├── (1, 2) + └── subquery + └── values + ├── columns: column3:3 + ├── cardinality: [1 - 1] + ├── key: () + ├── fd: ()-->(3) + └── ((1, 2),) + +# Cannot eliminate non-constant values subquery. +norm expect-not=EliminateConstValueSubquery +SELECT (SELECT gen_random_uuid()) +---- +values + ├── columns: gen_random_uuid:2 + ├── cardinality: [1 - 1] + ├── volatile + ├── key: () + ├── fd: ()-->(2) + └── tuple + └── subquery + └── values + ├── columns: gen_random_uuid:1 + ├── cardinality: [1 - 1] + ├── volatile + ├── key: () + ├── fd: ()-->(1) + └── (gen_random_uuid(),) diff --git a/pkg/sql/opt/norm/testdata/rules/udf b/pkg/sql/opt/norm/testdata/rules/udf index cc729d7952b5..7c15d53dc26c 100644 --- a/pkg/sql/opt/norm/testdata/rules/udf +++ b/pkg/sql/opt/norm/testdata/rules/udf @@ -46,16 +46,9 @@ norm format=show-scalars SELECT strict_fn(1, 'foo', true) ---- values - ├── columns: strict_fn:5 + ├── columns: strict_fn:5!null ├── cardinality: [1 - 1] ├── key: () ├── fd: ()-->(5) └── tuple - └── subquery - └── values - ├── columns: i:4!null - ├── cardinality: [1 - 1] - ├── key: () - ├── fd: ()-->(4) - └── tuple - └── const: 1 + └── const: 1 diff --git a/pkg/sql/opt/norm/testdata/rules/with b/pkg/sql/opt/norm/testdata/rules/with index b2fbeeda1d67..567648da114c 100644 --- a/pkg/sql/opt/norm/testdata/rules/with +++ b/pkg/sql/opt/norm/testdata/rules/with @@ -143,27 +143,11 @@ norm expect=InlineWith WITH foo AS (SELECT 1), bar AS (SELECT 2) SELECT (SELECT * FROM foo) + (SELECT * FROM bar) ---- values - ├── columns: "?column?":5 + ├── columns: "?column?":5!null ├── cardinality: [1 - 1] - ├── immutable ├── key: () ├── fd: ()-->(5) - └── tuple - └── plus - ├── subquery - │ └── values - │ ├── columns: "?column?":3!null - │ ├── cardinality: [1 - 1] - │ ├── key: () - │ ├── fd: ()-->(3) - │ └── (1,) - └── subquery - └── values - ├── columns: "?column?":4!null - ├── cardinality: [1 - 1] - ├── key: () - ├── fd: ()-->(4) - └── (2,) + └── (3,) norm expect=InlineWith WITH foo AS (SELECT 1), bar AS (SELECT 2) SELECT (SELECT * FROM foo) + (SELECT * FROM bar) + (SELECT * FROM bar) @@ -190,20 +174,14 @@ with &2 (bar) └── plus ├── plus │ ├── subquery - │ │ └── values - │ │ ├── columns: "?column?":3!null + │ │ └── with-scan &2 (bar) + │ │ ├── columns: "?column?":4!null + │ │ ├── mapping: + │ │ │ └── "?column?":2 => "?column?":4 │ │ ├── cardinality: [1 - 1] │ │ ├── key: () - │ │ ├── fd: ()-->(3) - │ │ └── (1,) - │ └── subquery - │ └── with-scan &2 (bar) - │ ├── columns: "?column?":4!null - │ ├── mapping: - │ │ └── "?column?":2 => "?column?":4 - │ ├── cardinality: [1 - 1] - │ ├── key: () - │ └── fd: ()-->(4) + │ │ └── fd: ()-->(4) + │ └── 1 └── subquery └── with-scan &2 (bar) ├── columns: "?column?":5!null @@ -417,14 +395,7 @@ anti-join-apply │ ├── outer: (2) │ ├── cardinality: [2 - 2] │ ├── (k:2,) - │ └── tuple - │ └── subquery - │ └── values - │ ├── columns: column1:9!null - │ ├── cardinality: [1 - 1] - │ ├── key: () - │ ├── fd: ()-->(9) - │ └── (1,) + │ └── (1,) └── filters └── column1:10 = k:2 [outer=(2,10), constraints=(/2: (/NULL - ]; /10: (/NULL - ]), fd=(2)==(10), (10)==(2)]