From 9129400255e9b060aa9aa78203471c8ab7d77c5f Mon Sep 17 00:00:00 2001 From: Mark Sirek Date: Sun, 13 Aug 2023 20:16:12 -0700 Subject: [PATCH] xform: opt test for insert fast path checks This commit adds an insert transformation rules test which displays optimized fast path checks which are built in the optbuilder and later explored and optimized. This test is modified in a later commit to test for rule firing. Epic: CRDB-26290 Informs: #58047 Release note: None --- pkg/sql/opt/xform/testdata/rules/insert | 424 ++++++++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100644 pkg/sql/opt/xform/testdata/rules/insert diff --git a/pkg/sql/opt/xform/testdata/rules/insert b/pkg/sql/opt/xform/testdata/rules/insert new file mode 100644 index 000000000000..5ba8c8849651 --- /dev/null +++ b/pkg/sql/opt/xform/testdata/rules/insert @@ -0,0 +1,424 @@ +#################### +# InsertFastPath # +#################### + +exec-ddl +CREATE TABLE t ( + k INT PRIMARY KEY, + r STRING NOT NULL, + a INT, + b INT, + INDEX (r, a) WHERE k != 1, + UNIQUE WITHOUT INDEX (a) WHERE k != 1, + CHECK (r IN ('east', 'west')) +) +---- + +# Fast path is not allowed when there is a UNIQUE WITHOUT INDEX with a +# partial index predicate. +opt format=show-fastpathchecks +INSERT INTO t VALUES (1, 'east', 10, 100) +---- +insert t + ├── columns: + ├── insert-mapping: + │ ├── column1:7 => t.k:1 + │ ├── column2:8 => t.r:2 + │ ├── column3:9 => t.a:3 + │ └── column4:10 => t.b:4 + ├── check columns: check1:11 + ├── partial index put columns: partial_index_put1:12 + ├── cardinality: [0 - 0] + ├── volatile, mutations + ├── values + │ ├── columns: column1:7!null column2:8!null column3:9!null column4:10!null check1:11!null partial_index_put1:12!null + │ ├── cardinality: [1 - 1] + │ ├── key: () + │ ├── fd: ()-->(7-12) + │ └── (1, 'east', 10, 100, true, false) + ├── unique-checks + │ └── unique-checks-item: t(a) + │ └── values + │ ├── columns: a:21!null + │ ├── cardinality: [0 - 0] + │ ├── key: () + │ └── fd: ()-->(21) + └── fast-path-unique-checks + └── fast-path-unique-checks-item: &{0 0 [] [] { record best-effort}} + └── values + ├── cardinality: [0 - 0] + └── key: () + +exec-ddl +DROP TABLE t +---- + +exec-ddl +CREATE TABLE t ( + k INT PRIMARY KEY, + r STRING NOT NULL, + a INT, + b INT AS (k % 9) STORED, + c INT, + INDEX (b, a), + INDEX (r, c), + UNIQUE WITHOUT INDEX (a), + UNIQUE WITHOUT INDEX (c), + CHECK (r IN ('east', 'west')) +) +---- + +# A computed leading index column allows fast path uniqueness checks. +# Note, the best-cost fast path check relation selected may not be one +# which would enable fast path uniqueness checks. +opt format=show-fastpathchecks +INSERT INTO t (k, r, a, c) VALUES (2, 'east', 10, 20) +---- +insert t + ├── columns: + ├── insert-mapping: + │ ├── column1:8 => t.k:1 + │ ├── column2:9 => t.r:2 + │ ├── column3:10 => t.a:3 + │ ├── b_comp:12 => t.b:4 + │ └── column4:11 => t.c:5 + ├── check columns: check1:13 + ├── cardinality: [0 - 0] + ├── volatile, mutations + ├── values + │ ├── columns: column1:8!null column2:9!null column3:10!null column4:11!null b_comp:12!null check1:13!null + │ ├── cardinality: [1 - 1] + │ ├── key: () + │ ├── fd: ()-->(8-13) + │ └── (2, 'east', 10, 20, 2, true) + ├── unique-checks + │ ├── unique-checks-item: t(a) + │ │ └── project + │ │ ├── columns: a:23!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(23) + │ │ └── project + │ │ ├── columns: a:23!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(23) + │ │ └── inner-join (cross) + │ │ ├── columns: t.k:14!null t.a:16!null a:23!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ │ ├── key: () + │ │ ├── fd: ()-->(14,16,23) + │ │ ├── values + │ │ │ ├── columns: a:23!null + │ │ │ ├── cardinality: [1 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(23) + │ │ │ └── (10,) + │ │ ├── limit + │ │ │ ├── columns: t.k:14!null t.a:16!null + │ │ │ ├── cardinality: [0 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(14,16) + │ │ │ ├── select + │ │ │ │ ├── columns: t.k:14!null t.a:16!null + │ │ │ │ ├── key: (14) + │ │ │ │ ├── fd: ()-->(16) + │ │ │ │ ├── limit hint: 1.00 + │ │ │ │ ├── scan t + │ │ │ │ │ ├── columns: t.k:14!null t.a:16 + │ │ │ │ │ ├── constraint: /14 + │ │ │ │ │ │ ├── [ - /1] + │ │ │ │ │ │ └── [/3 - ] + │ │ │ │ │ ├── key: (14) + │ │ │ │ │ ├── fd: (14)-->(16) + │ │ │ │ │ └── limit hint: 35.71 + │ │ │ │ └── filters + │ │ │ │ └── t.a:16 = 10 [outer=(16), constraints=(/16: [/10 - /10]; tight), fd=()-->(16)] + │ │ │ └── 1 + │ │ └── filters (true) + │ └── unique-checks-item: t(c) + │ └── project + │ ├── columns: c:44!null + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(44) + │ └── project + │ ├── columns: c:44!null + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(44) + │ └── inner-join (cross) + │ ├── columns: t.k:33!null t.c:37!null c:44!null + │ ├── cardinality: [0 - 1] + │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ ├── key: () + │ ├── fd: ()-->(33,37,44) + │ ├── values + │ │ ├── columns: c:44!null + │ │ ├── cardinality: [1 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(44) + │ │ └── (20,) + │ ├── scan t@t_r_c_idx + │ │ ├── columns: t.k:33!null t.c:37!null + │ │ ├── constraint: /34/37/33 + │ │ │ ├── [/'east'/20 - /'east'/20/1] + │ │ │ ├── [/'east'/20/3 - /'east'/20] + │ │ │ ├── [/'west'/20 - /'west'/20/1] + │ │ │ └── [/'west'/20/3 - /'west'/20] + │ │ ├── limit: 1 + │ │ ├── key: () + │ │ └── fd: ()-->(33,37) + │ └── filters (true) + └── fast-path-unique-checks + ├── fast-path-unique-checks-item: &{0 0 [] [] { record best-effort}} + │ └── select + │ ├── columns: t.k:26!null t.r:27!null t.a:28!null t.b:29 t.c:30 + │ ├── key: (26) + │ ├── fd: ()-->(28), (26)-->(27,29,30) + │ ├── index-join t + │ │ ├── columns: t.k:26!null t.r:27!null t.a:28 t.b:29 t.c:30 + │ │ ├── key: (26) + │ │ ├── fd: (26)-->(27-30) + │ │ └── scan t@t_r_c_idx + │ │ ├── columns: t.k:26!null t.r:27!null t.c:30 + │ │ ├── constraint: /27/30/26 + │ │ │ ├── [/'east' - /'east'] + │ │ │ └── [/'west' - /'west'] + │ │ ├── key: (26) + │ │ └── fd: (26)-->(27,30) + │ └── filters + │ └── t.a:28 = 10 [outer=(28), constraints=(/28: [/10 - /10]; tight), fd=()-->(28)] + └── fast-path-unique-checks-item: &{0 0 [] [] { record best-effort}} + └── index-join t + ├── columns: t.k:45!null t.r:46!null t.a:47 t.b:48 t.c:49!null + ├── key: (45) + ├── fd: ()-->(49), (45)-->(46-48) + └── scan t@t_r_c_idx + ├── columns: t.k:45!null t.r:46!null t.c:49!null + ├── constraint: /46/49/45 + │ ├── [/'east'/20 - /'east'/20] + │ └── [/'west'/20 - /'west'/20] + ├── key: (45) + └── fd: ()-->(49), (45)-->(46) + +exec-ddl +DROP TABLE t +---- + +exec-ddl +CREATE TABLE t ( + k INT PRIMARY KEY, + r STRING NOT NULL, + a INT, + b INT AS (k % 9) STORED, + INDEX (a), + INDEX (r, a, b), + INDEX (b, a), + UNIQUE WITHOUT INDEX (a), + UNIQUE WITHOUT INDEX (b), + UNIQUE WITHOUT INDEX (r, a, b), + UNIQUE WITHOUT INDEX (a, b), + CHECK (r IN ('east', 'west')) +) +---- + +# An insert to a table with multiple unique without index checks can build +# fast path checks for all of them. +opt format=show-fastpathchecks +INSERT INTO t (k, r, a) VALUES (2, 'east', 10) +---- +insert t + ├── columns: + ├── insert-mapping: + │ ├── column1:7 => t.k:1 + │ ├── column2:8 => t.r:2 + │ ├── column3:9 => t.a:3 + │ └── b_comp:10 => t.b:4 + ├── check columns: check1:11 + ├── cardinality: [0 - 0] + ├── volatile, mutations + ├── values + │ ├── columns: column1:7!null column2:8!null column3:9!null b_comp:10!null check1:11!null + │ ├── cardinality: [1 - 1] + │ ├── key: () + │ ├── fd: ()-->(7-11) + │ └── (2, 'east', 10, 2, true) + ├── unique-checks + │ ├── unique-checks-item: t(a) + │ │ └── project + │ │ ├── columns: a:20!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(20) + │ │ └── project + │ │ ├── columns: a:20!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(20) + │ │ └── inner-join (cross) + │ │ ├── columns: t.k:12!null t.a:14!null a:20!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ │ ├── key: () + │ │ ├── fd: ()-->(12,14,20) + │ │ ├── values + │ │ │ ├── columns: a:20!null + │ │ │ ├── cardinality: [1 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(20) + │ │ │ └── (10,) + │ │ ├── scan t@t_a_idx + │ │ │ ├── columns: t.k:12!null t.a:14!null + │ │ │ ├── constraint: /14/12 + │ │ │ │ ├── [/10 - /10/1] + │ │ │ │ └── [/10/3 - /10] + │ │ │ ├── limit: 1 + │ │ │ ├── key: () + │ │ │ └── fd: ()-->(12,14) + │ │ └── filters (true) + │ ├── unique-checks-item: t(b) + │ │ └── project + │ │ ├── columns: b:37!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(37) + │ │ └── project + │ │ ├── columns: b:37!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(37) + │ │ └── inner-join (cross) + │ │ ├── columns: t.k:28!null t.b:31!null b:37!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ │ ├── key: () + │ │ ├── fd: ()-->(28,31,37) + │ │ ├── values + │ │ │ ├── columns: b:37!null + │ │ │ ├── cardinality: [1 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(37) + │ │ │ └── (2,) + │ │ ├── limit + │ │ │ ├── columns: t.k:28!null t.b:31!null + │ │ │ ├── cardinality: [0 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(28,31) + │ │ │ ├── select + │ │ │ │ ├── columns: t.k:28!null t.b:31!null + │ │ │ │ ├── key: (28) + │ │ │ │ ├── fd: ()-->(31) + │ │ │ │ ├── limit hint: 1.00 + │ │ │ │ ├── scan t@t_b_a_idx + │ │ │ │ │ ├── columns: t.k:28!null t.b:31!null + │ │ │ │ │ ├── constraint: /31/30/28: [/2 - /2] + │ │ │ │ │ ├── key: (28) + │ │ │ │ │ ├── fd: ()-->(31) + │ │ │ │ │ └── limit hint: 1.07 + │ │ │ │ └── filters + │ │ │ │ └── t.k:28 != 2 [outer=(28), constraints=(/28: (/NULL - /1] [/3 - ]; tight)] + │ │ │ └── 1 + │ │ └── filters (true) + │ ├── unique-checks-item: t(r,a,b) + │ │ └── project + │ │ ├── columns: r:51!null a:52!null b:53!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(51-53) + │ │ └── project + │ │ ├── columns: r:51!null a:52!null b:53!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(51-53) + │ │ └── inner-join (cross) + │ │ ├── columns: t.k:44!null t.r:45!null t.a:46!null t.b:47!null r:51!null a:52!null b:53!null + │ │ ├── cardinality: [0 - 1] + │ │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ │ ├── key: () + │ │ ├── fd: ()-->(44-47,51-53) + │ │ ├── values + │ │ │ ├── columns: r:51!null a:52!null b:53!null + │ │ │ ├── cardinality: [1 - 1] + │ │ │ ├── key: () + │ │ │ ├── fd: ()-->(51-53) + │ │ │ └── ('east', 10, 2) + │ │ ├── scan t@t_r_a_b_idx + │ │ │ ├── columns: t.k:44!null t.r:45!null t.a:46!null t.b:47!null + │ │ │ ├── constraint: /45/46/47/44 + │ │ │ │ ├── [/'east'/10/2 - /'east'/10/2/1] + │ │ │ │ └── [/'east'/10/2/3 - /'east'/10/2] + │ │ │ ├── limit: 1 + │ │ │ ├── key: () + │ │ │ └── fd: ()-->(44-47) + │ │ └── filters (true) + │ └── unique-checks-item: t(a,b) + │ └── project + │ ├── columns: a:68!null b:69!null + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(68,69) + │ └── project + │ ├── columns: a:68!null b:69!null + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(68,69) + │ └── inner-join (cross) + │ ├── columns: t.k:60!null t.a:62!null t.b:63!null a:68!null b:69!null + │ ├── cardinality: [0 - 1] + │ ├── multiplicity: left-rows(zero-or-one), right-rows(exactly-one) + │ ├── key: () + │ ├── fd: ()-->(60,62,63,68,69) + │ ├── values + │ │ ├── columns: a:68!null b:69!null + │ │ ├── cardinality: [1 - 1] + │ │ ├── key: () + │ │ ├── fd: ()-->(68,69) + │ │ └── (10, 2) + │ ├── scan t@t_b_a_idx + │ │ ├── columns: t.k:60!null t.a:62!null t.b:63!null + │ │ ├── constraint: /63/62/60 + │ │ │ ├── [/2/10 - /2/10/1] + │ │ │ └── [/2/10/3 - /2/10] + │ │ ├── limit: 1 + │ │ ├── key: () + │ │ └── fd: ()-->(60,62,63) + │ └── filters (true) + └── fast-path-unique-checks + ├── fast-path-unique-checks-item: &{0 0 [] [] { record best-effort}} + │ └── scan t@t_r_a_b_idx + │ ├── columns: t.k:22!null t.r:23!null t.a:24!null t.b:25 + │ ├── constraint: /23/24/25/22 + │ │ ├── [/'east'/10 - /'east'/10] + │ │ └── [/'west'/10 - /'west'/10] + │ ├── key: (22) + │ └── fd: ()-->(24), (22)-->(23,25) + ├── fast-path-unique-checks-item: &{0 0 [] [] { record best-effort}} + │ └── select + │ ├── columns: t.k:38!null t.r:39!null t.a:40 t.b:41!null + │ ├── key: (38) + │ ├── fd: ()-->(41), (38)-->(39,40) + │ ├── scan t@t_r_a_b_idx + │ │ ├── columns: t.k:38!null t.r:39!null t.a:40 t.b:41 + │ │ ├── constraint: /39/40/41/38 + │ │ │ ├── [/'east' - /'east'] + │ │ │ └── [/'west' - /'west'] + │ │ ├── key: (38) + │ │ └── fd: (38)-->(39-41) + │ └── filters + │ └── t.b:41 = 2 [outer=(41), constraints=(/41: [/2 - /2]; tight), fd=()-->(41)] + ├── fast-path-unique-checks-item: &{0 0 [] [] { record best-effort}} + │ └── scan t@t_r_a_b_idx + │ ├── columns: t.k:54!null t.r:55!null t.a:56!null t.b:57!null + │ ├── constraint: /55/56/57/54: [/'east'/10/2 - /'east'/10/2] + │ ├── key: (54) + │ └── fd: ()-->(55-57) + └── fast-path-unique-checks-item: &{0 0 [] [] { record best-effort}} + └── scan t@t_r_a_b_idx + ├── columns: t.k:70!null t.r:71!null t.a:72!null t.b:73!null + ├── constraint: /71/72/73/70 + │ ├── [/'east'/10/2 - /'east'/10/2] + │ └── [/'west'/10/2 - /'west'/10/2] + ├── key: (70) + └── fd: ()-->(72,73), (70)-->(71)