From 5ff0d0567c7682d7ee6be9097dc211f1b7aaeaef Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Mon, 21 Sep 2020 12:09:23 -0700 Subject: [PATCH] opt: calculate stats for partial spatial indexes This commit updates the statistics builder so that partial index predicates of spatial indexes are considered when calculating the statistics for spatial index scans. Release note: None --- .../inverted_filter_geospatial_dist | 12 +- .../logic_test/inverted_index_geospatial | 6 +- .../exec/execbuilder/testdata/inverted_index | 4 +- pkg/sql/opt/memo/statistics_builder.go | 57 +- pkg/sql/opt/memo/testdata/stats/inverted-geo | 38 +- .../memo/testdata/stats/partial-index-scan | 515 ++++++++++++++++++ .../testdata/external/postgis-tutorial-idx | 196 ++++--- 7 files changed, 693 insertions(+), 135 deletions(-) diff --git a/pkg/sql/logictest/testdata/logic_test/inverted_filter_geospatial_dist b/pkg/sql/logictest/testdata/logic_test/inverted_filter_geospatial_dist index db12b25a7353..59bc5b6ef46f 100644 --- a/pkg/sql/logictest/testdata/logic_test/inverted_filter_geospatial_dist +++ b/pkg/sql/logictest/testdata/logic_test/inverted_filter_geospatial_dist @@ -35,7 +35,7 @@ query T SELECT url FROM [EXPLAIN (DISTSQL) SELECT k FROM geo_table WHERE ST_Intersects('MULTIPOINT((2.2 2.2), (3.0 3.0))'::geometry, geom) ORDER BY k] ---- -https://cockroachdb.github.io/distsqlplan/decode.html#eJyUU19P2zAQf9-nsO6FVvNa2-m04afCCFumQlmaaUM4QllzYxHBzmx3yoT63ackDGhRC70HJ_fnd3e_O90tuN8lSJiFk_BDQha2JMfx9IRchN_PJgfRKekdRbNk9mXSJ3ch113AFZpLn_0okXz7FMYhcf6y0B6tw7l3vb2Tr5MkOptGp0mvJwaCiIHoU9ILBowEA9bv70n5MZyehEl8TptcN30yjY_CmByek-sUKGiT42l2gw7kBXBIKVTWzNE5YxvTbRsQ5TVIRqHQ1cI35pTC3FgEeQu-8CWChKRpMsYsRztkQCFHnxVlm_aew7jp4LLQOdZAYVZl2kkyVHCoVP0zV6rmTKmaPffAm10xXAHJdE4CRoz_hdZBuqRgFv6Bj_PZFYLkS_pyzpH-g9ZjflyUHi3aIV8l_t8f1pUlRpMxl8Q1rInzmfWyZRG8e6sUE0wpxp57gKDOd4U15NfYU5guvCRjvnEOYpc5fDaFvlu92LT6yhY3mf37UJqOxcbqwS7VZ8Z6tMNgtfKYvwYK3Wbk-tkwzkasE3H35Yx3P_sH-_fC-OiJ_hC5Iu9HT_Q9-fj6xqL_grmPdmEeo6uMdrjCfFNmtkwpYH6F3V07s7BzPLNm3pbp1GmLaw05Ot95eadEunM1DT4G861gsR0stoKD7eBgK3i0Bk6Xr_4FAAD__2cps3E= +https://cockroachdb.github.io/distsqlplan/decode.html#eJyUU11P2zAUfd-vsO4Ljea1dtJpw0-FEbZMhbA004ZwhLLmjkUEO7PdKRPqf5-SMKBFLdQPTu7HObnnOL4F-7sCAbNwGn5IycJU5DiJT8hF-P1sehCdksFRNEtnX6YeuWu57huuUF-6_EeF5NunMAmJdZelcmgszp0d7J18nabRWRydpoOBP_SJP_Q9SgbBkJFgyDxvT4iPYXwSpsk5bbluPBInR2FCDs_JdQYUlC7wNL9BC-ICOGQUaqPnaK02beq2a4iKBgSjUKp64dp0RmGuDYK4BVe6CkFA2g6ZYF6gGTGgUKDLy6qjvdcwaSe4LFWBDVCY1bmygowkHErZ_CykbDiTsmHPbfBmVwyXQHJVkIAR7X6hsZAtKeiFe9BjXX6FIPiSvlxzpP6gcVgcl5VDg2bEV4X_r4dNbYhWZMIFsa1qYl1unOhUBO_eSsl8JiVjz21AUBW7wlrxa-opxAsnyIRv9MHfxYfPulR3R-9vOvralDe5-QsUerfE-q_MOBuzfvl3T854_7J_sH-_GB8_iR86V9b78ZN4Tzy-ERPfe4EXwS5ezLRxaEbBqg8T_noj_XgX-gRtrZXFFfpNzGyZUcDiCvurbPXCzPHM6Hn3mT6MO1yXKNC6vsr7IFJ9qR3wMZhvBfvbwf5WcLAdHGwFj9fA2fLVvwAAAP__ks-wYA== # The inverted filterer handles five inverted index rows with decoded # datums, where the first column is the PK (k) and the second is the cellid @@ -65,7 +65,7 @@ query T SELECT url FROM [EXPLAIN (DISTSQL) SELECT k FROM geo_table WHERE ST_Intersects('MULTIPOINT((2.2 2.2), (3.0 3.0))'::geometry, geom) ORDER BY k] ---- -https://cockroachdb.github.io/distsqlplan/decode.html#eJyUU19P2zAQf9-nsO6FVvNa2-m04afCCFumQlmaaUM4QllzYxHBzmx3yoT63ackDGhRC70HJ_fnd3e_O90tuN8lSJiFk_BDQha2JMfx9IRchN_PJgfRKekdRbNk9mXSJ3ch113AFZpLn_0okXz7FMYhcf6y0B6tw7l3vb2Tr5MkOptGp0mvJwaCiIHoU9ILBowEA9bv70n5MZyehEl8TptcN30yjY_CmByek-sUKGiT42l2gw7kBXBIKVTWzNE5YxvTbRsQ5TVIRqHQ1cI35pTC3FgEeQu-8CWChKRpMsYsRztkQCFHnxVlm_aew7jp4LLQOdZAYVZl2kkyVHCoVP0zV6rmTKmaPffAm10xXAHJdE4CRoz_hdZBuqRgFv6Bj_PZFYLkS_pyzpH-g9ZjflyUHi3aIV8l_t8f1pUlRpMxl8Q1rInzmfWyZRG8e6sUE0wpxp57gKDOd4U15NfYU5guvCRjvnEOYpc5fDaFvlu92LT6yhY3mf37UJqOxcbqwS7VZ8Z6tMNgtfKYvwYK3Wbk-tkwzkasE3H35Yx3P_sH-_fC-OiJ_hC5Iu9HT_Q9-fj6xqL_grmPdmEeo6uMdrjCfFNmtkwpYH6F3V07s7BzPLNm3pbp1GmLaw05Ot95eadEunM1DT4G861gsR0stoKD7eBgK3i0Bk6Xr_4FAAD__2cps3E= +https://cockroachdb.github.io/distsqlplan/decode.html#eJyUU11P2zAUfd-vsO4Ljea1dtJpw0-FEbZMhbA004ZwhLLmjkUEO7PdKRPqf5-SMKBFLdQPTu7HObnnOL4F-7sCAbNwGn5IycJU5DiJT8hF-P1sehCdksFRNEtnX6YeuWu57huuUF-6_EeF5NunMAmJdZelcmgszp0d7J18nabRWRydpoOBP_SJP_Q9SgbBkJFgyDxvT4iPYXwSpsk5bbluPBInR2FCDs_JdQYUlC7wNL9BC-ICOGQUaqPnaK02beq2a4iKBgSjUKp64dp0RmGuDYK4BVe6CkFA2g6ZYF6gGTGgUKDLy6qjvdcwaSe4LFWBDVCY1bmygowkHErZ_CykbDiTsmHPbfBmVwyXQHJVkIAR7X6hsZAtKeiFe9BjXX6FIPiSvlxzpP6gcVgcl5VDg2bEV4X_r4dNbYhWZMIFsa1qYl1unOhUBO_eSsl8JiVjz21AUBW7wlrxa-opxAsnyIRv9MHfxYfPulR3R-9vOvralDe5-QsUerfE-q_MOBuzfvl3T854_7J_sH-_GB8_iR86V9b78ZN4Tzy-ERPfe4EXwS5ezLRxaEbBqg8T_noj_XgX-gRtrZXFFfpNzGyZUcDiCvurbPXCzPHM6Hn3mT6MO1yXKNC6vsr7IFJ9qR3wMZhvBfvbwf5WcLAdHGwFj9fA2fLVvwAAAP__ks-wYA== statement ok ALTER INDEX geo_table@geom_index EXPERIMENTAL_RELOCATE VALUES (ARRAY[2], 1152921574000000000) @@ -89,7 +89,7 @@ query T SELECT url FROM [EXPLAIN (DISTSQL) SELECT k FROM geo_table WHERE ST_Intersects('MULTIPOINT((2.2 2.2), (3.0 3.0))'::geometry, geom) ORDER BY k] ---- -https://cockroachdb.github.io/distsqlplan/decode.html#eJyUU19P2zAQf9-nsO6FVvNa2-m04afCCFumQlmaaUM4QllzYxHBzmx3yoT63ackDGhRC70HJ_fnd3e_O90tuN8lSJiFk_BDQha2JMfx9IRchN_PJgfRKekdRbNk9mXSJ3ch113AFZpLn_0okXz7FMYhcf6y0B6tw7l3vb2Tr5MkOptGp0mvJwaCiIHoU9ILBowEA9bv70n5MZyehEl8TptcN30yjY_CmByek-sUKGiT42l2gw7kBXBIKVTWzNE5YxvTbRsQ5TVIRqHQ1cI35pTC3FgEeQu-8CWChKRpMsYsRztkQCFHnxVlm_aew7jp4LLQOdZAYVZl2kkyVHCoVP0zV6rmTKmaPffAm10xXAHJdE4CRoz_hdZBuqRgFv6Bj_PZFYLkS_pyzpH-g9ZjflyUHi3aIV8l_t8f1pUlRpMxl8Q1rInzmfWyZRG8e6sUE0wpxp57gKDOd4U15NfYU5guvCRjvnEOYpc5fDaFvlu92LT6yhY3mf37UJqOxcbqwS7VZ8Z6tMNgtfKYvwYK3Wbk-tkwzkasE3H35Yx3P_sH-_fC-OiJ_hC5Iu9HT_Q9-fj6xqL_grmPdmEeo6uMdrjCfFNmtkwpYH6F3V07s7BzPLNm3pbp1GmLaw05Ot95eadEunM1DT4G861gsR0stoKD7eBgK3i0Bk6Xr_4FAAD__2cps3E= +https://cockroachdb.github.io/distsqlplan/decode.html#eJyUU11P2zAUfd-vsO4Ljea1dtJpw0-FEbZMhbA004ZwhLLmjkUEO7PdKRPqf5-SMKBFLdQPTu7HObnnOL4F-7sCAbNwGn5IycJU5DiJT8hF-P1sehCdksFRNEtnX6YeuWu57huuUF-6_EeF5NunMAmJdZelcmgszp0d7J18nabRWRydpoOBP_SJP_Q9SgbBkJFgyDxvT4iPYXwSpsk5bbluPBInR2FCDs_JdQYUlC7wNL9BC-ICOGQUaqPnaK02beq2a4iKBgSjUKp64dp0RmGuDYK4BVe6CkFA2g6ZYF6gGTGgUKDLy6qjvdcwaSe4LFWBDVCY1bmygowkHErZ_CykbDiTsmHPbfBmVwyXQHJVkIAR7X6hsZAtKeiFe9BjXX6FIPiSvlxzpP6gcVgcl5VDg2bEV4X_r4dNbYhWZMIFsa1qYl1unOhUBO_eSsl8JiVjz21AUBW7wlrxa-opxAsnyIRv9MHfxYfPulR3R-9vOvralDe5-QsUerfE-q_MOBuzfvl3T854_7J_sH-_GB8_iR86V9b78ZN4Tzy-ERPfe4EXwS5ezLRxaEbBqg8T_noj_XgX-gRtrZXFFfpNzGyZUcDiCvurbPXCzPHM6Hn3mT6MO1yXKNC6vsr7IFJ9qR3wMZhvBfvbwf5WcLAdHGwFj9fA2fLVvwAAAP__ks-wYA== # Data is distributed, but the filterer can't be distributed since it is not a union. query I @@ -102,7 +102,7 @@ query T SELECT url FROM [EXPLAIN (DISTSQL) SELECT k FROM geo_table WHERE ST_CoveredBy('MULTIPOINT((2.2 2.2), (3.0 3.0))'::geometry, geom) ORDER BY k] ---- -https://cockroachdb.github.io/distsqlplan/decode.html#eJyUU99P2z4Qf__-Fda90OrrtbbTacNPhRG2TIWyNNOGcIRCfWMRIc5sFwWh_u9TEgYU1ELvwcn9-Nzd5053B-5PARJm4ST8lJCFLchhPD0iZ-HPk8ledEx6B9EsmX2b9Ml9yFUXcInm3GcXBZIfX8I4JM6fz80NWtQXt72do--TJDqZRsdJrycGgoiB6FPSCwaMBAPW7-9I-TmcHoVJfEqbVNd9Mo0Pwpjsn5KrFCiURuNxdo0O5BlwSClU1szROWMb010bEOkaJKOQl9XCN-aUwtxYBHkHPvcFgoSk6THGTKMdMqCg0Wd50aZ9oDBuOjjPS401UJhVWekkGSrYV6r-pZWqOVOqZq898G5bDFdAslKTgBHjf6N1kC4pmIV_5ON8dokg-ZK-nXNU3qD1qA_zwqNFO-SrxP_5w7qyxJRkzCVxDWvifGa9bFkEH94rxQRTirHXHiBY6m1hDfln7ClMF16SMV87B7HNHL6avLxfvVi3-srm15m9fSxNx2Jt9WCb6jNjPdphsFp5zP8HCt1m5LOrYZyNWCfi_ssZ735293YfhPHRC_0xckU-jl7oO_Lp8Y1F_w1jH21DPEZXmdLhCvF1mdkypYD6EruzdmZh53hizbwt06nTFtcaNDrfeXmnRGXnahp8CuYbwWIzWGwEB5vBwUbw6Bk4Xf73NwAA__-VlLJv +https://cockroachdb.github.io/distsqlplan/decode.html#eJyUU19P2z4Uff99Cuu-0OjntXbSacNPhRG2TIWwNNOGcIRCfcciQpzZLgpC_e5TEgYU1EL94OT-OSf3HMd3YP-UIGAWTsNPKVmYkhwm8RE5C3-eTPeiYzI4iGbp7NvUI_ctV33DJepzl1-USH58CZOQWHc-1zdoUF3cDnaOvk_T6CSOjtPBwB_6xB_6HiWDYMhIMGSetyPE5zA-CtPklLZU1x6Jk4MwIfun5CoDCpVWeJxfowVxBhwyCrXRc7RWmzZ11zVEqgHBKBRVvXBtOqMw1wZB3IErXIkgIG1nTDBXaEYMKCh0eVF2tA8SJu0E50WlsAEKszqvrCAjCftSNr-UlA1nUjbstQ3ebYvhEkheKRIwot1vNBayJQW9cI96rMsvEQRf0rdrjqobNA7VYVE6NGhGfFX4v3rY1Iboiky4ILZVTazLjROdiuDDeymZz6Rk7LUNCFZqW1gr_pl6CvHCCTLha33wt_Hhqy6q-6P31x19bYrr3NwChd4t8exPZpyNWb_8-ydnvH_Z3dt9WIyPX8SPnSvr4_hFvCOeXoiJ773BimAbK2baODSjYNWGCf9_Lf14G_oEba0riyv065jZMqOA6hL7m2z1wszxxOh595k-jDtcl1BoXV_lfRBVfakd8CmYbwT7m8H-RnCwGRxsBI-fgbPlf38DAAD__7lKr14= # Move all the index data that will be read to node 2 while the query executes # at node 1. The filtering moves to node 2 when it is distributable. @@ -129,7 +129,7 @@ query T SELECT url FROM [EXPLAIN (DISTSQL) SELECT k FROM geo_table WHERE ST_Intersects('MULTIPOINT((2.2 2.2), (3.0 3.0))'::geometry, geom) ORDER BY k] ---- -https://cockroachdb.github.io/distsqlplan/decode.html#eJyUlFFP2zAQx9_3Kax7odVMaztBG34qjLBlKi1LO20IVyhrbiyi2JntTplQv_uUhAEFNaV-cHL2_e7yv9PlDtzvBUiYRMPow5Qs7YKcJuMzchl9Px8exSPSOYkn08mXYZfcu9w0Dtdornz6Y4Hk26coiYjzV7n2aB3OvevsnX0dTuPzcTyadjqiJ4joiS4lnaDHSNBj3e6elB-j8Vk0TS5oFeu2S8bJSZSQ4wtyMwMK2mQ4Sm_RgbwEDhQEzCgU1szROWOr47vaKc5KkIxCroulr45nFObGIsg78LlfIEgYmX1T9EOgkKFP80XttqJglv4Rcj69RpAHK_okMG8PPK0qkGCaoe2ztfDwUKBBJe8q1xmWQGFSpNpJ0ldwrFT5M1Oq5Eypkm3bYH9Xhisgqc5IwIjxv9A62KSZ76I51n_QesxO84VHi7bP14X_v4_KwhKjyYBL4irVxPnUelmrCN4dKMUEU4qxbRsQ1NmuWCX-mXoK46WXZMA31kHsUofPJtf3rRebWl_Y_Da1fx9T04HYmD3YJfvEWI-2H6xnHvC3QKHpjHw-k4yzkDVL3D85483L4dHhw2I8fGE_eq6t9-ELe08-He2B6L6i7uGa8i3DnKArjHb4qmlmqxkFzK6x-WE4s7RzPLdmXqdpzHHN1QcZOt_cHjRGrJur6gOfwrwVFu2waIWDdjhohcN2OGyF2TN4tnrzLwAA__-ZiOWI +https://cockroachdb.github.io/distsqlplan/decode.html#eJyUlFFP2zAQx9_3Kax7odVMaztBG34qjLBlKi1LO20IVyhrbiyi2JntTplQv_uUhAEFNaV-cHu--13y_1uXO3C_FyBhEg2jD1OytAtymozPyGX0_Xx4FI9I5ySeTCdfhl1yX3LTFFyjufLpjwWSb5-iJCLOX-Xao3U4966zd_Z1OI3Px_Fo2umIniCiJ7qUdIIeI0GPdbt7Un6MxmfRNLmgVa_bLhknJ1FCji_IzQwoaJPhKL1FB_ISOFAQMKNQWDNH54ytju_qojgrQTIKuS6WvjqeUZgbiyDvwOd-gSBhZPZN0Q-BQoY-zRd12YqCWfpHyPn0GkEerOiTxry98bRyIME0Q9tna-3hwaBBJe8q1xmWQGFSpNpJ0ldwrFT5M1Oq5Eypkm3bYH9Xhisgqc5IwIjxv9A62KSZ76I51n_QesxO84VHi7bP14X_z0dlYYnRZMAlcZVq4nxqvaxVBO8OlGKCKcXYtg0I6mxXrBL_TD2F8dJLMuAbfRC7-PDZ5Pr-6sWmqy9sfpvav0ChcUs-nxPGWciaJe5_OePNn8Ojw4fFePgifqxcW-_DF_GefDpuA9F9hRfBLl5MjPVo-8G6DwP-dmP7cK39lvlN0BVGO3zVALPVjAJm19h8I5xZ2jmeWzOvH9OE45qrDzJ0vskeNEGsm1T1gk9h3gqLdli0wkE7HLTCYTsctsLsGTxbvfkXAAD__4th4nc= query I SELECT k FROM geo_table WHERE ST_CoveredBy('MULTIPOINT((2.2 2.2), (3.0 3.0))'::geometry, geom) ORDER BY k @@ -142,7 +142,7 @@ query T SELECT url FROM [EXPLAIN (DISTSQL) SELECT k FROM geo_table WHERE ST_CoveredBy('MULTIPOINT((2.2 2.2), (3.0 3.0))'::geometry, geom) ORDER BY k] ---- -https://cockroachdb.github.io/distsqlplan/decode.html#eJyUlNFP2z4Qx99_f4V1L7T6mdZ2gjb8VBhhy1RalnbaEK5QqG8sosSZ7aIg1P99SsKAghqoH5ycfZ-7fO90uQf3ZwESJtEw-jQlS7sgx8n4hJxHP0-HB_GIdI7iyXTybdglDy7XjcMVmgufXi6Q_PgSJRFx_mJubtGivrzr7Jx8H07j03E8mnY6oieI6IkuJZ2gx0jQY93ujpSfo_FJNE3OaBXqpkvGyVGUkMMzcj0DCrnROEpv0IE8Bw4UBMwoFNbM0Tljq-P72inWJUhGIcuLpa-OZxTmxiLIe_CZXyBIGJldU_RDoKDRp9midltRMEv_BDmfXiHIvRV9Fpi3B55WBUgw1Wj7bC08PNZnUMm7yHKNJVCYFGnuJOkrOFSq_KWVKjlTqmRvbbC7LcMVkDTXJGDE-N9oHWzSzLfRHOe3aD3q42zh0aLt83Xh_-6jsrDE5GTAJXGVauJ8ar2sVQQf9pRiginF2FsbEMz1tlgl_oV6CuOll2TAN9ZBbFOHrybLH1ovNrW-sNlNau-eUtOB2Jg92Cb7xFiPth-sZx7w_4FC0xn5YiQZZyFrlnh4csabl_2D_cfFePjKfvJcWx_DV_aOfD7ZA9F9R9nDNeFvzHKCrjC5w3cNM1vNKKC-wuZ_4czSzvHUmnmdpjHHNVcfaHS-ud1rjDhvrqoPfA7zVli0w6IVDtrhoBUO2-GwFWYv4Nnqv78BAAD__z445IY= +https://cockroachdb.github.io/distsqlplan/decode.html#eJyUlNFP2z4Qx99_f4V1L7T6mdZ2gjb8VBhhy1RalnbaEK5QqG8sosSZ7aIg1P99SsKAghqoH9ye7z6XfL_W5R7cnwVImETD6NOULO2CHCfjE3Ie_TwdHsQj0jmKJ9PJt2GXPJRcNwVXaC58erlA8uNLlETE-Yu5uUWL-vKus3PyfTiNT8fxaNrpiJ4goie6lHSCHiNBj3W7O1J-jsYn0TQ5o1Wrmy4ZJ0dRQg7PyPUMKORG4yi9QQfyHDhQEDCjUFgzR-eMrY7v66JYlyAZhSwvlr46nlGYG4sg78FnfoEgYWR2TdEPgYJGn2aLumxFwSz9E-R8eoUg91b0WWPe3nhaGZBgqtH22Vp7ePRnUMm7yHKNJVCYFGnuJOkrOFSq_KWVKjlTqmRvbbC7LcMVkDTXJGDE-N9oHWzSzLfRHOe3aD3q42zh0aLt83Xh__JRWVhicjLgkrhKNXE-tV7WKoIPe0oxwZRi7K0NCOZ6W6wS_0I9hfHSSzLgG30Q2_jw1WT5w9WLTVdf2OwmtXdAoXFLvhgTxlnImiUefjnjzZ_9g_3HxXj4Kn6qXFsfw1fxjnw-bQPRfYcVwTZWTIz1aPvBug0D_v_G9uFa-zfGN0FXmNzhu-aXrWYUUF9h84lwZmnneGrNvH5ME45rrj7Q6HyT3WuCOG9S1Qs-h3krLNph0QoH7XDQCoftcNgKsxfwbPXf3wAAAP__KCLhdQ== # Bounding box operations. statement ok diff --git a/pkg/sql/logictest/testdata/logic_test/inverted_index_geospatial b/pkg/sql/logictest/testdata/logic_test/inverted_index_geospatial index f213ad03d27d..c2cdb2833a9d 100644 --- a/pkg/sql/logictest/testdata/logic_test/inverted_index_geospatial +++ b/pkg/sql/logictest/testdata/logic_test/inverted_index_geospatial @@ -28,7 +28,7 @@ SELECT k FROM geo_table WHERE ST_Intersects('SRID=26918;POINT(400003 4000003)':: query T SELECT url FROM [EXPLAIN ANALYZE SELECT k FROM geo_table WHERE ST_Intersects('SRID=26918;POINT(400003 4000003)'::geometry, geom) ORDER BY k] ---- -https://cockroachdb.github.io/distsqlplan/decode.html#eJyUVGFP2zAQ_b5fcbovUM1T7STriqdJLRC2bqVlaaWNkQqF5sYikriz3S0I9b9PSWDQQgvtB1e-u-e89-7sGzS_U5Q48vv-wRjmOoWjYHgMZ_73k363N4DuoNs__eHD7mFvNB597TfgtvSqLrwkdW6ji5Tg2yc_8MHY8yS3pA1NrdndGQW9ww9Oa0-0358Me4Pxrsc55y5Uf9xt7Ej50R8e--PglJVnZQ0YBod-APuncDVBhrmKaRBlZFCeocAJw5lWUzJG6TJ0UxX04gIlZ5jks7ktwxOGU6UJ5Q3axKaEEsclyYCimHSTI8OYbJSk1bH_NXRKBudJHlOBDEezKDcSmiHuh2HxMw7DQvAwLPhzC77ZFiNChCiPweWg7C_SBhlq9deApiiW4CFDY6M0BZtkJIGX-YtrS3cFjteGfZwsGKq5vffA2OiSUIoFe7lPvfwPaUvxUZJa0qSbYtmsu7xfzDSoHDpCgimdAmMjbWWl3H33Ngy5w8OQ8-cWBMrjbWGlYY8cG86thI54gXdZVEBGmdLXMDdUGsjhS7LeQWcbBz-rJL8dNGfdoM10kkX6-p406zjLvJ2neFejCStVdXCldp0SdxslI6Ut6aa7rKIjXiPDej7k6oXngovyajvcabX2-MPfQasr2p6oN23eFm3P8z2xIx--AR2nsa6TTzryqJNicye9bfQHZGYqN7Skf93JfDFhSPEl1e-SUXM9pROtptVn6u2wwlWBmIyts6Le9PI6VRJ8CBYbwc5msLMR7G4GuxvB3gp4snj1LwAA__8OjPdQ +https://cockroachdb.github.io/distsqlplan/decode.html#eJyUlFFv0zAQx9_5FKd72SqMaiehdEZI7bYMAl070kowlmrKmmNES-Jiu5Bp6ndHSTbYOtqteXDku_s7f__syw2anxlKHPsD_2ACC53BUTg6hjP_68mgHwyhP-wPTr_5sHsYjCfjz4MW3JZeNYWXpM5tfJERfPnghz4Ye54WlrShmTW7O-MwOHzndPZE9-3JKBhOdj3OOXehfnG3tSPle3907E_CU1atlbdgFB76IeyfwtUUGRYqoWGck0F5hgKnDOdazcgYpavQTV0QJCVKzjAt5gtbhacMZ0oTyhu0qc0IJU4qkyHFCek2R4YJ2TjN6mX_7qFXOThPi4RKZDiex4WR0I5wP4rK70kUlYJHUcmfGvDVthoRIcRFAi4HZX-QNshQq98GNMWJBA8ZGhtnGdg0Jwm8yl9cW7orcLwu7ON0yVAt7D8GxsaXhFIs2fM5BcUv0paSozSzpEm3xUNYd3m_nGtQBfSEBFORAmNjbWW9c_fN6yjiDo8izp8aEKhItpVVwB4RGy2shJ54Brs8LiGnXOlrWBiqAHL4lK4n6GxD8KNKi9uL5qy7aHOd5rG-RoYNZ7naOFxwUbWIw51OZ4_ffw46fdH1RDPp8q7oep7viR15v5d6TmsdEed_ROpLDytVTXCldh0jdxtGY6Ut6bb7kE9PvHyG1UeHJzYfnreNsZDMXBWGHhhbtzJfThlScknNr8iohZ7RiVaz-jPNdFTr6kBCxjZZ0UyCoklVBu-LxUaxs1nsbBS7m8XuRrG3Ip4uX_wJAAD__58c9D8= statement ok DROP TABLE geo_table @@ -64,7 +64,7 @@ SELECT k FROM geo_table WHERE ST_Intersects('SRID=26918;POINT(400003 4000003)':: query T SELECT url FROM [EXPLAIN ANALYZE SELECT k FROM geo_table WHERE ST_Intersects('SRID=26918;POINT(400003 4000003)'::geometry, geom) ORDER BY k] ---- -https://cockroachdb.github.io/distsqlplan/decode.html#eJykVGFP2zoU_f5-xdX9AtXzU-0kr6_4aVILhK1baVlaaWOkQqG5YxFJ3NnuVoT63ycnMKBTM6r1gyvfe87NPcfXvkPzNUeJk3AYHk1hqXM4icancBF-PBv2ByPoj_rD808h7B8PJtPJ-2EL7qE3NfCa1KVNrnKCD2_CKARjL7PSkjY0t2Z_bxINjl95nQPR_f9sPBhN9wPOOfeh-uN-a0_K1-H4NJxG58zVKlowjo7DCA7P4WaGDEuV0igpyKC8QIEzhgut5mSM0i50VwEG6QolZ5iVi6V14RnDudKE8g5tZnNCiVPXZERJSrrNkWFKNsnyquxPDT3XwWVWprRChpNFUhoJ7RgP43j1OY3jFffdwn-z4D-7ckSMkJQp-ByU_ULaIEOtvhvQlKQSPGRobJLnYLOCJHCXv7q19AAQXgCHOFszVEv76IGxyTWhFGv2cp8G5TfSltKTLLekSbfFc7Me8uFqoUGV0BMSjHMKjE20lZVy_79_45g75dwJbFwQqEx3pTnDfnFsvLQSeuIF3hXJCgoqlL6FpSGH4vAu2-6gt4uDb1VW3g-at23QFjorEn372DTreS_ouxpN2EDVwQ3sNiX-LkomSlvSbf-5ip74GxnW8yE3LzwXXLir7XGv0zngT39Hnb7oBqLedHlXdIMgDMSefPoG9LzWn52kaD7JYBf9EZmFKg0907-tMl_PGFJ6TfW7ZNRSz-lMq3n1mXo7rnhVICVj66yoN4OyTrkGn5JFI9lrJnuNZL-Z7DeSgw3ybP3XjwAAAP__-mH3Sw== +https://cockroachdb.github.io/distsqlplan/decode.html#eJyclFFv0zAQx9_5FKd72SqCaiehdEZI7bYMAl070kowlmrKmmNES-Jiu9Bp6ndHTjZYixpW8uDId_-_c_eznTvU33MUOA4GwdEEFiqHk2h0ChfB57NBPxxCf9gfnH8JYP84HE_GHwctuJfe1MJrkpcmucoJPr0LogC0ucxKQ0rTzOj9vXEUHr9xOwe8-_psFA4n-z5jjHlQvZjX2hPibTA6DSbRuWPXKlowio6DCA7P4WaKDpYypWFSkEZxgRynDs6VnJHWUtnQXSUI0yUK5mBWzhfGhqcOzqQiFHdoMpMTCpzYIiNKUlJthg6mZJIsr5b93UPPVnCZlSkt0cHxPCm1gHaMh3G8_JrG8ZJ5dmD_GPDFrh4eIyRlCh4Dab6R0uigkj81KEpSAS46qE2S52CyggQwm7-6NfQg4K4PhzhdOSgX5g8DbZJrQsFXztM5heUPUobSkyw3pEi1-Tqsh3ywnCuQJfS4AG1JgTaJMqLq3Hv1Mo6Z7ZzZBhsHBCrTXW0W2F_ERgsjoMefwK5IllBQIdUtLDRZFYMP2XaC7i4E38usvD9o7raDNldZkahbdLDmLDYvDuOM2yviMrfTOWCPn6NOn3d9Xk-6rMu7vh_4fE88vks9t7UTkerQw4aqDm5otzHydmE0lsqQanvrfHr8-f9sHm_ePH-XwiLSc1lqWits28psNXWQ0muqf0VaLtSMzpScVZ-pp6PKVwVS0qbO8noSlnXKFvjYzBvNbrPZbTR7zWav0exvmKerZ78CAAD__4tB9Do= # Also works when creating an index. statement ok @@ -76,4 +76,4 @@ CREATE INVERTED INDEX geom_index ON geo_table(geom) query T SELECT url FROM [EXPLAIN ANALYZE SELECT k FROM geo_table WHERE ST_Intersects('SRID=26918;POINT(400003 4000003)'::geometry, geom) ORDER BY k] ---- -https://cockroachdb.github.io/distsqlplan/decode.html#eJykVGFP2zoU_f5-xdX9AtXzU-0kr6_4aVILhK1baVlaaWOkQqG5YxFJ3NnuVoT63ycnMKBTM6r1gyvfe87NPcfXvkPzNUeJk3AYHk1hqXM4icancBF-PBv2ByPoj_rD808h7B8PJtPJ-2EL7qE3NfCa1KVNrnKCD2_CKARjL7PSkjY0t2Z_bxINjl95nQPR_f9sPBhN9wPOOfeh-uN-a0_K1-H4NJxG58zVKlowjo7DCA7P4WaGDEuV0igpyKC8QIEzhgut5mSM0i50VwEG6QolZ5iVi6V14RnDudKE8g5tZnNCiVPXZERJSrrNkWFKNsnyquxPDT3XwWVWprRChpNFUhoJ7RgP43j1OY3jFffdwn-z4D-7ckSMkJQp-ByU_ULaIEOtvhvQlKQSPGRobJLnYLOCJHCXv7q19AAQXgCHOFszVEv76IGxyTWhFGv2cp8G5TfSltKTLLekSbfFc7Me8uFqoUGV0BMSjHMKjE20lZVy_79_45g75dwJbFwQqEx3pTnDfnFsvLQSeuIF3hXJCgoqlL6FpSGH4vAu2-6gt4uDb1VW3g-at23QFjorEn372DTreS_ouxpN2EDVwQ3sNiX-LkomSlvSbf-5ip74GxnW8yE3LzwXXLir7XGv0zngT39Hnb7oBqLedHlXdIMgDMSefPoG9LzWn52kaD7JYBf9EZmFKg0907-tMl_PGFJ6TfW7ZNRSz-lMq3n1mXo7rnhVICVj66yoN4OyTrkGn5JFI9lrJnuNZL-Z7DeSgw3ybP3XjwAAAP__-mH3Sw== +https://cockroachdb.github.io/distsqlplan/decode.html#eJyclFFv0zAQx9_5FKd72SqCaiehdEZI7bYMAl070kowlmrKmmNES-Jiu9Bp6ndHTjZYixpW8uDId_-_c_eznTvU33MUOA4GwdEEFiqHk2h0ChfB57NBPxxCf9gfnH8JYP84HE_GHwctuJfe1MJrkpcmucoJPr0LogC0ucxKQ0rTzOj9vXEUHr9xOwe8-_psFA4n-z5jjHlQvZjX2hPibTA6DSbRuWPXKlowio6DCA7P4WaKDpYypWFSkEZxgRynDs6VnJHWUtnQXSUI0yUK5mBWzhfGhqcOzqQiFHdoMpMTCpzYIiNKUlJthg6mZJIsr5b93UPPVnCZlSkt0cHxPCm1gHaMh3G8_JrG8ZJ5dmD_GPDFrh4eIyRlCh4Dab6R0uigkj81KEpSAS46qE2S52CyggQwm7-6NfQg4K4PhzhdOSgX5g8DbZJrQsFXztM5heUPUobSkyw3pEi1-Tqsh3ywnCuQJfS4AG1JgTaJMqLq3Hv1Mo6Z7ZzZBhsHBCrTXW0W2F_ERgsjoMefwK5IllBQIdUtLDRZFYMP2XaC7i4E38usvD9o7raDNldZkahbdLDmLDYvDuOM2yviMrfTOWCPn6NOn3d9Xk-6rMu7vh_4fE88vks9t7UTkerQw4aqDm5otzHydmE0lsqQanvrfHr8-f9sHm_ePH-XwiLSc1lqWits28psNXWQ0muqf0VaLtSMzpScVZ-pp6PKVwVS0qbO8noSlnXKFvjYzBvNbrPZbTR7zWav0exvmKerZ78CAAD__4tB9Do= diff --git a/pkg/sql/opt/exec/execbuilder/testdata/inverted_index b/pkg/sql/opt/exec/execbuilder/testdata/inverted_index index 2109fd9dafea..e52d4fd204ee 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/inverted_index +++ b/pkg/sql/opt/exec/execbuilder/testdata/inverted_index @@ -644,9 +644,9 @@ EXPLAIN (VERBOSE) SELECT k FROM geo_table WHERE ST_Intersects('POINT(3.0 3.0)':: · distribution local · · · vectorized false · · project · · (k) · - │ estimated row count 330 (missing stats) · · + │ estimated row count 110 (missing stats) · · └── filter · · (k, geom) · - │ estimated row count 330 (missing stats) · · + │ estimated row count 110 (missing stats) · · │ filter st_intersects('010100000000000000000008400000000000000840', geom) · · └── index join · · (k, geom) · │ estimated row count 111 (missing stats) · · diff --git a/pkg/sql/opt/memo/statistics_builder.go b/pkg/sql/opt/memo/statistics_builder.go index f0ec88938280..1c2a4b3fe75b 100644 --- a/pkg/sql/opt/memo/statistics_builder.go +++ b/pkg/sql/opt/memo/statistics_builder.go @@ -656,8 +656,7 @@ func (sb *statisticsBuilder) buildScan(scan *ScanExpr, relProps *props.Relationa // the constraint selectivity and the partial index predicate (if it exists) // to the underlying table stats. if scan.InvertedConstraint != nil { - // TODO(mjibson): support partial index predicates for inverted constraints. - sb.invertedConstrainScan(scan, relProps) + sb.invertedConstrainScan(scan, pred, relProps) sb.finalizeFromCardinality(relProps) return } @@ -789,7 +788,9 @@ func (sb *statisticsBuilder) constrainScan( // invertedConstrainScan is called from buildScan to calculate the stats for // the scan based on the given inverted constraint. -func (sb *statisticsBuilder) invertedConstrainScan(scan *ScanExpr, relProps *props.Relational) { +func (sb *statisticsBuilder) invertedConstrainScan( + scan *ScanExpr, pred FiltersExpr, relProps *props.Relational, +) { s := &relProps.Stats // Calculate distinct counts and histograms for constrained columns @@ -831,14 +832,41 @@ func (sb *statisticsBuilder) invertedConstrainScan(scan *ScanExpr, relProps *pro numUnappliedConjuncts += 2 } - // Inverted indexes don't contain NULLs, so we do not need to have - // updateNullCountsFromNotNullCols or selectivityFromNullsRemoved here. + // Set null counts to 0 for non-nullable columns + // --------------------------------------------- + // Inverted indexes don't contain NULLs, so there is no need to try to + // determine not-null columns from the constraint. However, the partial + // index predicate may guarantee that non-indexed columns are not-null. + notNullCols := relProps.NotNullCols.Copy() + if pred != nil { + // Add any not-null columns from the predicate constraints. + for i := range pred { + if c := pred[i].ScalarProps().Constraints; c != nil { + cols := c.ExtractNotNullCols(sb.evalCtx) + const distinctCount = math.MaxFloat64 + sb.ensureColStat(cols, distinctCount, scan, s) + notNullCols.UnionWith(cols) + } + } + } + sb.updateNullCountsFromNotNullCols(notNullCols, s) + + // Calculate distinct counts and histograms for the partial index predicate + // ------------------------------------------------------------------------ + if pred != nil { + predUnappliedConjucts, predConstrainedCols, predHistCols := sb.applyFilter(pred, scan, relProps) + numUnappliedConjuncts += predUnappliedConjucts + constrainedCols.UnionWith(predConstrainedCols) + constrainedCols = sb.tryReduceCols(constrainedCols, s, &scan.Relational().FuncDeps) + histCols.UnionWith(predHistCols) + } // Calculate row count and selectivity // ----------------------------------- s.ApplySelectivity(sb.selectivityFromHistograms(histCols, scan, s)) s.ApplySelectivity(sb.selectivityFromMultiColDistinctCounts(constrainedCols, scan, s)) s.ApplySelectivity(sb.selectivityFromUnappliedConjuncts(numUnappliedConjuncts)) + s.ApplySelectivity(sb.selectivityFromNullsRemoved(scan, notNullCols, constrainedCols)) // Adjust the selectivity so we don't double-count the histogram columns. s.ApplySelectivity(1.0 / sb.selectivityFromSingleColDistinctCounts(histCols, scan, s)) @@ -2995,6 +3023,12 @@ func (sb *statisticsBuilder) applyFilter( histCols.UnionWith(histColsLocal) if !scalarProps.TightConstraints { numUnappliedConjuncts++ + // Mimic invertedConstrainScan in the case of no histogram + // information that assumes a geo function is a single closed + // span that corresponds to two "conjuncts". + if isGeoIndexScanCond(conjunct.Condition) { + numUnappliedConjuncts++ + } } } else { numUnappliedConjuncts++ @@ -3942,6 +3976,19 @@ func isGeoIndexJoinCond(cond opt.ScalarExpr) bool { return false } +// isGeoIndexScanCond returns true if the given condition is an +// index-accelerated geospatial function with one variable argument. +func isGeoIndexScanCond(cond opt.ScalarExpr) bool { + if fn, ok := cond.(*FunctionExpr); ok { + if _, ok := geoindex.RelationshipMap[fn.Name]; ok && len(fn.Args) >= 2 { + firstIsVar := fn.Args[0].Op() == opt.VariableOp + secondIsVar := fn.Args[1].Op() == opt.VariableOp + return (firstIsVar && !secondIsVar) || (!firstIsVar && secondIsVar) + } + } + return false +} + func hasGeoIndexJoinCond(filters FiltersExpr) bool { for i := range filters { if isGeoIndexJoinCond(filters[i].Condition) { diff --git a/pkg/sql/opt/memo/testdata/stats/inverted-geo b/pkg/sql/opt/memo/testdata/stats/inverted-geo index 01378940495a..9b0befe7dad4 100644 --- a/pkg/sql/opt/memo/testdata/stats/inverted-geo +++ b/pkg/sql/opt/memo/testdata/stats/inverted-geo @@ -73,13 +73,13 @@ project ├── sort │ ├── columns: i:1(int) g:2(geometry!null) │ ├── immutable - │ ├── stats: [rows=666.666667, distinct(2)=7, null(2)=0] + │ ├── stats: [rows=222.222222, distinct(2)=7, null(2)=0] │ ├── ordering: +1 │ ├── limit hint: 1.00 │ └── select │ ├── columns: i:1(int) g:2(geometry!null) │ ├── immutable - │ ├── stats: [rows=666.666667, distinct(2)=7, null(2)=0] + │ ├── stats: [rows=222.222222, distinct(2)=7, null(2)=0] │ ├── scan t │ │ ├── columns: i:1(int) g:2(geometry) │ │ └── stats: [rows=2000, distinct(2)=7, null(2)=0] @@ -94,22 +94,22 @@ memo (optimized, ~11KB, required=[presentation: i:1]) ├── G1: (project G2 G3 i) │ └── [presentation: i:1] │ ├── best: (project G2 G3 i) - │ └── cost: 4262.50 + │ └── cost: 4163.18 ├── G2: (limit G4 G5 ordering=+1) │ └── [] │ ├── best: (limit G4="[ordering: +1] [limit hint: 1.00]" G5 ordering=+1) - │ └── cost: 4262.48 + │ └── cost: 4163.16 ├── G3: (projections) ├── G4: (select G6 G7) (select G8 G7) │ ├── [ordering: +1] [limit hint: 1.00] │ │ ├── best: (sort G4) - │ │ └── cost: 4262.46 + │ │ └── cost: 4163.14 │ └── [] │ ├── best: (select G6 G7) │ └── cost: 4124.04 ├── G5: (const 1) ├── G6: (scan t,cols=(1,2)) - │ ├── [ordering: +1] [limit hint: 3.00] + │ ├── [ordering: +1] [limit hint: 9.00] │ │ ├── best: (sort G6) │ │ └── cost: 2582.66 │ └── [] @@ -117,7 +117,7 @@ memo (optimized, ~11KB, required=[presentation: i:1]) │ └── cost: 2104.02 ├── G7: (filters G9) ├── G8: (index-join G10 t,cols=(1,2)) - │ ├── [ordering: +1] [limit hint: 4.50] + │ ├── [ordering: +1] [limit hint: 13.50] │ │ ├── best: (sort G8) │ │ └── cost: 22095.08 │ └── [] @@ -159,7 +159,7 @@ project ├── select │ ├── columns: i:1(int) g:2(geometry!null) │ ├── immutable - │ ├── stats: [rows=666.666667, distinct(2)=7, null(2)=0] + │ ├── stats: [rows=222.222222, distinct(2)=7, null(2)=0] │ ├── ordering: +1 │ ├── limit hint: 1.00 │ ├── sort @@ -213,7 +213,7 @@ memo (optimized, ~11KB, required=[presentation: i:1]) │ └── cost: 4.05 ├── G5: (const 1) ├── G6: (scan t,cols=(1,2)) - │ ├── [ordering: +1] [limit hint: 3.00] + │ ├── [ordering: +1] [limit hint: 9.00] │ │ ├── best: (sort G6) │ │ └── cost: 2582.66 │ └── [] @@ -328,7 +328,7 @@ project ├── columns: i:1(int) ├── cardinality: [0 - 1] ├── immutable - ├── stats: [rows=1, distinct(1)=0.999851422, null(1)=0.025, distinct(2)=0.932539762, null(2)=0] + ├── stats: [rows=1, distinct(1)=0.999867838, null(1)=0.025, distinct(2)=0.933913991, null(2)=0] ├── key: () ├── fd: ()-->(1) └── limit @@ -336,19 +336,19 @@ project ├── internal-ordering: +1 ├── cardinality: [0 - 1] ├── immutable - ├── stats: [rows=1, distinct(1)=0.999851422, null(1)=0.025, distinct(2)=0.932539762, null(2)=0] + ├── stats: [rows=1, distinct(1)=0.999867838, null(1)=0.025, distinct(2)=0.933913991, null(2)=0] ├── key: () ├── fd: ()-->(1,2) ├── sort │ ├── columns: i:1(int) g:2(geometry!null) │ ├── immutable - │ ├── stats: [rows=633.333333, distinct(1)=533.055556, null(1)=15.8333333, distinct(2)=7, null(2)=0] + │ ├── stats: [rows=211.111111, distinct(1)=199.969136, null(1)=5.27777778, distinct(2)=7, null(2)=0] │ ├── ordering: +1 │ ├── limit hint: 1.00 │ └── select │ ├── columns: i:1(int) g:2(geometry!null) │ ├── immutable - │ ├── stats: [rows=633.333333, distinct(1)=533.055556, null(1)=15.8333333, distinct(2)=7, null(2)=0] + │ ├── stats: [rows=211.111111, distinct(1)=199.969136, null(1)=5.27777778, distinct(2)=7, null(2)=0] │ ├── scan t │ │ ├── columns: i:1(int) g:2(geometry) │ │ └── stats: [rows=2000, distinct(1)=1000, null(1)=50, distinct(2)=7, null(2)=100] @@ -364,7 +364,7 @@ project ├── columns: i:1(int) ├── cardinality: [0 - 1] ├── immutable - ├── stats: [rows=1, distinct(1)=0.999851422, null(1)=0.025, distinct(2)=0.932539762, null(2)=0] + ├── stats: [rows=1, distinct(1)=0.999867838, null(1)=0.025, distinct(2)=0.933913991, null(2)=0] ├── key: () ├── fd: ()-->(1) └── limit @@ -372,13 +372,13 @@ project ├── internal-ordering: +1 ├── cardinality: [0 - 1] ├── immutable - ├── stats: [rows=1, distinct(1)=0.999851422, null(1)=0.025, distinct(2)=0.932539762, null(2)=0] + ├── stats: [rows=1, distinct(1)=0.999867838, null(1)=0.025, distinct(2)=0.933913991, null(2)=0] ├── key: () ├── fd: ()-->(1,2) ├── select │ ├── columns: i:1(int) g:2(geometry!null) │ ├── immutable - │ ├── stats: [rows=633.333333, distinct(1)=533.055556, null(1)=15.8333333, distinct(2)=7, null(2)=0] + │ ├── stats: [rows=211.111111, distinct(1)=199.969136, null(1)=5.27777778, distinct(2)=7, null(2)=0] │ ├── ordering: +1 │ ├── limit hint: 1.00 │ ├── sort @@ -461,7 +461,7 @@ SELECT * FROM t WHERE st_intersects('LINESTRING(.5 .5, .7 .7)', g) select ├── columns: i:1(int) g:2(geometry!null) ├── immutable - ├── stats: [rows=33.3333333, distinct(1)=28.7528606, null(1)=30, distinct(2)=4, null(2)=0] + ├── stats: [rows=11.1111111, distinct(1)=10.5717006, null(1)=10, distinct(2)=4, null(2)=0] ├── index-join t │ ├── columns: i:1(int) g:2(geometry) │ ├── stats: [rows=100] @@ -499,11 +499,11 @@ SELECT i FROM t@secondary WHERE st_intersects('LINESTRING(.5 .5, .7 .7)', g) project ├── columns: i:1(int) ├── immutable - ├── stats: [rows=33.3333333] + ├── stats: [rows=11.1111111] └── select ├── columns: i:1(int) g:2(geometry!null) ├── immutable - ├── stats: [rows=33.3333333, distinct(2)=4, null(2)=0] + ├── stats: [rows=11.1111111, distinct(2)=4, null(2)=0] ├── index-join t │ ├── columns: i:1(int) g:2(geometry) │ ├── stats: [rows=100] diff --git a/pkg/sql/opt/memo/testdata/stats/partial-index-scan b/pkg/sql/opt/memo/testdata/stats/partial-index-scan index 4c848a250836..fbabee6fa3c1 100644 --- a/pkg/sql/opt/memo/testdata/stats/partial-index-scan +++ b/pkg/sql/opt/memo/testdata/stats/partial-index-scan @@ -1113,3 +1113,518 @@ select │ └── key: (1) └── filters └── (i:2 > 0) AND (i:2 <= 100) [type=bool, outer=(2), constraints=(/2: [/1 - /100]; tight)] + +# ---------------------------------------------------------- +# Tests for partial inverted spatial indexes +# ---------------------------------------------------------- + +exec-ddl +CREATE TABLE spatial ( + k INT PRIMARY KEY, + g GEOMETRY, + s STRING, + INVERTED INDEX i (g), + INVERTED INDEX p (g) WHERE s IN ('apple', 'banana', 'cherry') +) +---- + +# Add non-histogram stats. +exec-ddl +ALTER TABLE spatial INJECT STATISTICS '[ + { + "columns": ["g"], + "created_at": "2018-01-01 1:00:00.00000+00:00", + "row_count": 2000, + "distinct_count": 7, + "null_count": 0 + }, + { + "columns": ["s"], + "created_at": "2018-01-01 1:00:00.00000+00:00", + "row_count": 2000, + "distinct_count": 40, + "null_count": 0 + } +]' +---- + +# The partial index should be preferred over the non-partial index or PK. +opt +SELECT k FROM spatial WHERE st_intersects('LINESTRING(0.5 0.5, 0.7 0.7)', g) AND s IN ('apple', 'banana', 'cherry') +---- +project + ├── columns: k:1(int!null) + ├── immutable + ├── stats: [rows=16.6666667] + ├── key: (1) + └── select + ├── columns: k:1(int!null) g:2(geometry!null) s:3(string!null) + ├── immutable + ├── stats: [rows=16.6666667, distinct(2)=7, null(2)=0, distinct(3)=3, null(3)=0] + ├── key: (1) + ├── fd: (1)-->(2,3) + ├── index-join spatial + │ ├── columns: k:1(int!null) g:2(geometry) s:3(string) + │ ├── stats: [rows=16.6666667] + │ ├── key: (1) + │ ├── fd: (1)-->(2,3) + │ └── inverted-filter + │ ├── columns: k:1(int!null) + │ ├── inverted expression: /6 + │ │ ├── tight: false + │ │ └── union spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── pre-filterer expression + │ │ └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool] + │ ├── stats: [rows=16.6666667] + │ ├── key: (1) + │ └── scan spatial@p,partial + │ ├── columns: k:1(int!null) g_inverted_key:6(geometry!null) + │ ├── inverted constraint: /6/1 + │ │ └── spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── stats: [rows=16.6666667, distinct(1)=16.6666667, null(1)=0, distinct(3)=3, null(3)=0, distinct(6)=16.6666667, null(6)=0] + │ ├── key: (1) + │ └── fd: (1)-->(6) + └── filters + └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool, outer=(2), immutable, constraints=(/2: (/NULL - ])] + +# The partial index should be preferred over the non-partial index or PK when +# there is an additional filter to apply on s. +opt +SELECT k FROM spatial WHERE st_intersects('LINESTRING(0.5 0.5, 0.7 0.7)', g) AND s = 'banana' +---- +project + ├── columns: k:1(int!null) + ├── immutable + ├── stats: [rows=5.55555556] + ├── key: (1) + └── select + ├── columns: k:1(int!null) g:2(geometry!null) s:3(string!null) + ├── immutable + ├── stats: [rows=5.55555556, distinct(2)=5.55555556, null(2)=0, distinct(3)=1, null(3)=0] + ├── key: (1) + ├── fd: ()-->(3), (1)-->(2) + ├── index-join spatial + │ ├── columns: k:1(int!null) g:2(geometry) s:3(string) + │ ├── stats: [rows=16.6666667] + │ ├── key: (1) + │ ├── fd: (1)-->(2,3) + │ └── inverted-filter + │ ├── columns: k:1(int!null) + │ ├── inverted expression: /6 + │ │ ├── tight: false + │ │ └── union spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── pre-filterer expression + │ │ └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool] + │ ├── stats: [rows=16.6666667] + │ ├── key: (1) + │ └── scan spatial@p,partial + │ ├── columns: k:1(int!null) g_inverted_key:6(geometry!null) + │ ├── inverted constraint: /6/1 + │ │ └── spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── stats: [rows=16.6666667, distinct(1)=16.6666667, null(1)=0, distinct(3)=3, null(3)=0, distinct(6)=16.6666667, null(6)=0] + │ ├── key: (1) + │ └── fd: (1)-->(6) + └── filters + ├── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool, outer=(2), immutable, constraints=(/2: (/NULL - ])] + └── s:3 = 'banana' [type=bool, outer=(3), constraints=(/3: [/'banana' - /'banana']; tight), fd=()-->(3)] + +# Add null values for s. +exec-ddl +ALTER TABLE spatial INJECT STATISTICS '[ + { + "columns": ["g"], + "created_at": "2018-01-01 1:00:00.00000+00:00", + "row_count": 2000, + "distinct_count": 7, + "null_count": 0 + }, + { + "columns": ["s"], + "created_at": "2018-01-01 1:00:00.00000+00:00", + "row_count": 2000, + "distinct_count": 40, + "null_count": 1000 + } +]' +---- + +opt +SELECT k FROM spatial WHERE st_intersects('LINESTRING(0.5 0.5, 0.7 0.7)', g) AND s IN ('apple', 'banana', 'cherry') +---- +project + ├── columns: k:1(int!null) + ├── immutable + ├── stats: [rows=8.54700855] + ├── key: (1) + └── select + ├── columns: k:1(int!null) g:2(geometry!null) s:3(string!null) + ├── immutable + ├── stats: [rows=8.54700855, distinct(2)=7, null(2)=0, distinct(3)=3, null(3)=0] + ├── key: (1) + ├── fd: (1)-->(2,3) + ├── index-join spatial + │ ├── columns: k:1(int!null) g:2(geometry) s:3(string) + │ ├── stats: [rows=8.54700855] + │ ├── key: (1) + │ ├── fd: (1)-->(2,3) + │ └── inverted-filter + │ ├── columns: k:1(int!null) + │ ├── inverted expression: /6 + │ │ ├── tight: false + │ │ └── union spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── pre-filterer expression + │ │ └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool] + │ ├── stats: [rows=8.54700855] + │ ├── key: (1) + │ └── scan spatial@p,partial + │ ├── columns: k:1(int!null) g_inverted_key:6(geometry!null) + │ ├── inverted constraint: /6/1 + │ │ └── spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── stats: [rows=8.54700855, distinct(1)=8.54700855, null(1)=0, distinct(3)=3, null(3)=0, distinct(6)=8.54700855, null(6)=0] + │ ├── key: (1) + │ └── fd: (1)-->(6) + └── filters + └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool, outer=(2), immutable, constraints=(/2: (/NULL - ])] + +opt +SELECT k FROM spatial WHERE st_intersects('LINESTRING(0.5 0.5, 0.7 0.7)', g) AND s = 'banana' +---- +project + ├── columns: k:1(int!null) + ├── immutable + ├── stats: [rows=2.84900285] + ├── key: (1) + └── select + ├── columns: k:1(int!null) g:2(geometry!null) s:3(string!null) + ├── immutable + ├── stats: [rows=2.84900285, distinct(2)=2.84900285, null(2)=0, distinct(3)=1, null(3)=0] + ├── key: (1) + ├── fd: ()-->(3), (1)-->(2) + ├── index-join spatial + │ ├── columns: k:1(int!null) g:2(geometry) s:3(string) + │ ├── stats: [rows=8.54700855] + │ ├── key: (1) + │ ├── fd: (1)-->(2,3) + │ └── inverted-filter + │ ├── columns: k:1(int!null) + │ ├── inverted expression: /6 + │ │ ├── tight: false + │ │ └── union spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── pre-filterer expression + │ │ └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool] + │ ├── stats: [rows=8.54700855] + │ ├── key: (1) + │ └── scan spatial@p,partial + │ ├── columns: k:1(int!null) g_inverted_key:6(geometry!null) + │ ├── inverted constraint: /6/1 + │ │ └── spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── stats: [rows=8.54700855, distinct(1)=8.54700855, null(1)=0, distinct(3)=3, null(3)=0, distinct(6)=8.54700855, null(6)=0] + │ ├── key: (1) + │ └── fd: (1)-->(6) + └── filters + ├── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool, outer=(2), immutable, constraints=(/2: (/NULL - ])] + └── s:3 = 'banana' [type=bool, outer=(3), constraints=(/3: [/'banana' - /'banana']; tight), fd=()-->(3)] + +# Add histogram statistics. +# +# Histogram boundaries are from a `POLYGON((0.0 0.0, 1.0 0.0, 1.0 1.0, +# 0.0 1.0, 0.0 0.0))` row. The row_count is lower than the sum of the +# histogram's num_eq and num_range because there are more entries in +# the inverted index than rows in the table. +exec-ddl +ALTER TABLE spatial INJECT STATISTICS '[ + { + "columns": ["g"], + "created_at": "2018-01-01 1:00:00.00000+00:00", + "row_count": 2000, + "distinct_count": 7, + "null_count": 0, + "histo_col_type":"BYTES", + "histo_buckets":[ + {"num_eq": 1000, "num_range": 0, "distinct_range": 0, "upper_bound": "\\x42fd0555555555555555"}, + {"num_eq": 1000, "num_range": 1000, "distinct_range": 1, "upper_bound": "\\x42fd0fffffff00000000"}, + {"num_eq": 1000, "num_range": 1000, "distinct_range": 1, "upper_bound": "\\x42fd1000000100000000"}, + {"num_eq": 1000, "num_range": 1000, "distinct_range": 1, "upper_bound": "\\x42fd1aaaaaab00000000"} + ] + }, + { + "columns": ["s"], + "created_at": "2018-01-01 1:00:00.00000+00:00", + "row_count": 2000, + "distinct_count": 40, + "null_count": 0, + "histo_col_type": "string", + "histo_buckets": [ + {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "apple"}, + {"num_eq": 100, "num_range": 300, "distinct_range": 9, "upper_bound": "banana"}, + {"num_eq": 100, "num_range": 300, "distinct_range": 9, "upper_bound": "cherry"}, + {"num_eq": 200, "num_range": 400, "distinct_range": 9, "upper_bound": "mango"}, + {"num_eq": 200, "num_range": 400, "distinct_range": 9, "upper_bound": "pineapple"} + ] + } +]' +---- + +# The partial index should be preferred over the non-partial index or PK. +opt +SELECT k FROM spatial WHERE st_intersects('LINESTRING(0.5 0.5, 0.7 0.7)', g) AND s IN ('apple', 'banana', 'cherry') +---- +project + ├── columns: k:1(int!null) + ├── immutable + ├── stats: [rows=22.2222222] + ├── key: (1) + └── select + ├── columns: k:1(int!null) g:2(geometry!null) s:3(string!null) + ├── immutable + ├── stats: [rows=22.2222222, distinct(2)=7, null(2)=0, distinct(3)=2, null(3)=0] + │ histogram(3)= 0 11.111 0 11.111 + │ <--- 'banana' --- 'cherry' + ├── key: (1) + ├── fd: (1)-->(2,3) + ├── index-join spatial + │ ├── columns: k:1(int!null) g:2(geometry) s:3(string) + │ ├── stats: [rows=300] + │ ├── key: (1) + │ ├── fd: (1)-->(2,3) + │ └── inverted-filter + │ ├── columns: k:1(int!null) + │ ├── inverted expression: /6 + │ │ ├── tight: false + │ │ └── union spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── pre-filterer expression + │ │ └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool] + │ ├── stats: [rows=300] + │ ├── key: (1) + │ └── scan spatial@p,partial + │ ├── columns: k:1(int!null) g_inverted_key:6(geometry!null) + │ ├── inverted constraint: /6/1 + │ │ └── spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── stats: [rows=300, distinct(1)=85.7142857, null(1)=0, distinct(3)=2, null(3)=0, distinct(6)=3, null(6)=0, distinct(3,6)=6, null(3,6)=0] + │ │ histogram(3)= 0 100 0 100 + │ │ <--- 'banana' --- 'cherry' + │ │ histogram(6)= 0 0 50 0 50 100 50 0 0 0 50 0 + │ │ <--- '\x42fd1000000000000000' ---- '\x42fd1000000000000001' ---- '\x42fd1000000100000000' ---- '\x42fd1200000000000000' --- '\x42fd1400000000000000' ---- '\x42fd1400000000000001' + │ ├── key: (1) + │ └── fd: (1)-->(6) + └── filters + └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool, outer=(2), immutable, constraints=(/2: (/NULL - ])] + +# The partial index should be preferred over the non-partial index or PK when +# there is an additional filter to apply on s. +opt +SELECT k FROM spatial WHERE st_intersects('LINESTRING(0.5 0.5, 0.7 0.7)', g) AND s = 'banana' +---- +project + ├── columns: k:1(int!null) + ├── immutable + ├── stats: [rows=11.1111111] + ├── key: (1) + └── select + ├── columns: k:1(int!null) g:2(geometry!null) s:3(string!null) + ├── immutable + ├── stats: [rows=11.1111111, distinct(2)=7, null(2)=0, distinct(3)=1, null(3)=0] + │ histogram(3)= 0 11.111 + │ <--- 'banana' + ├── key: (1) + ├── fd: ()-->(3), (1)-->(2) + ├── index-join spatial + │ ├── columns: k:1(int!null) g:2(geometry) s:3(string) + │ ├── stats: [rows=300] + │ ├── key: (1) + │ ├── fd: (1)-->(2,3) + │ └── inverted-filter + │ ├── columns: k:1(int!null) + │ ├── inverted expression: /6 + │ │ ├── tight: false + │ │ └── union spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── pre-filterer expression + │ │ └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool] + │ ├── stats: [rows=300] + │ ├── key: (1) + │ └── scan spatial@p,partial + │ ├── columns: k:1(int!null) g_inverted_key:6(geometry!null) + │ ├── inverted constraint: /6/1 + │ │ └── spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── stats: [rows=300, distinct(1)=85.7142857, null(1)=0, distinct(3)=2, null(3)=0, distinct(6)=3, null(6)=0, distinct(3,6)=6, null(3,6)=0] + │ │ histogram(3)= 0 100 0 100 + │ │ <--- 'banana' --- 'cherry' + │ │ histogram(6)= 0 0 50 0 50 100 50 0 0 0 50 0 + │ │ <--- '\x42fd1000000000000000' ---- '\x42fd1000000000000001' ---- '\x42fd1000000100000000' ---- '\x42fd1200000000000000' --- '\x42fd1400000000000000' ---- '\x42fd1400000000000001' + │ ├── key: (1) + │ └── fd: (1)-->(6) + └── filters + ├── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool, outer=(2), immutable, constraints=(/2: (/NULL - ])] + └── s:3 = 'banana' [type=bool, outer=(3), constraints=(/3: [/'banana' - /'banana']; tight), fd=()-->(3)] + +# Add null values for s. +exec-ddl +ALTER TABLE spatial INJECT STATISTICS '[ + { + "columns": ["g"], + "created_at": "2018-01-01 1:00:00.00000+00:00", + "row_count": 2000, + "distinct_count": 7, + "null_count": 0, + "histo_col_type":"BYTES", + "histo_buckets":[ + {"num_eq": 1000, "num_range": 0, "distinct_range": 0, "upper_bound": "\\x42fd0555555555555555"}, + {"num_eq": 1000, "num_range": 1000, "distinct_range": 1, "upper_bound": "\\x42fd0fffffff00000000"}, + {"num_eq": 1000, "num_range": 1000, "distinct_range": 1, "upper_bound": "\\x42fd1000000100000000"}, + {"num_eq": 1000, "num_range": 1000, "distinct_range": 1, "upper_bound": "\\x42fd1aaaaaab00000000"} + ] + }, + { + "columns": ["s"], + "created_at": "2018-01-01 1:00:00.00000+00:00", + "row_count": 2000, + "distinct_count": 40, + "null_count": 100, + "histo_col_type": "string", + "histo_buckets": [ + {"num_eq": 0, "num_range": 0, "distinct_range": 0, "upper_bound": "apple"}, + {"num_eq": 100, "num_range": 200, "distinct_range": 9, "upper_bound": "banana"}, + {"num_eq": 100, "num_range": 300, "distinct_range": 9, "upper_bound": "cherry"}, + {"num_eq": 200, "num_range": 400, "distinct_range": 9, "upper_bound": "mango"}, + {"num_eq": 200, "num_range": 400, "distinct_range": 9, "upper_bound": "pineapple"} + ] + } +]' +---- + +opt +SELECT k FROM spatial WHERE st_intersects('LINESTRING(0.5 0.5, 0.7 0.7)', g) AND s IN ('apple', 'banana', 'cherry') +---- +project + ├── columns: k:1(int!null) + ├── immutable + ├── stats: [rows=22.2222222] + ├── key: (1) + └── select + ├── columns: k:1(int!null) g:2(geometry!null) s:3(string!null) + ├── immutable + ├── stats: [rows=22.2222222, distinct(2)=7, null(2)=0, distinct(3)=3, null(3)=0] + │ histogram(3)= 0 11.111 0 11.111 + │ <--- 'banana' --- 'cherry' + ├── key: (1) + ├── fd: (1)-->(2,3) + ├── index-join spatial + │ ├── columns: k:1(int!null) g:2(geometry) s:3(string) + │ ├── stats: [rows=307.105263] + │ ├── key: (1) + │ ├── fd: (1)-->(2,3) + │ └── inverted-filter + │ ├── columns: k:1(int!null) + │ ├── inverted expression: /6 + │ │ ├── tight: false + │ │ └── union spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── pre-filterer expression + │ │ └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool] + │ ├── stats: [rows=307.105263] + │ ├── key: (1) + │ └── scan spatial@p,partial + │ ├── columns: k:1(int!null) g_inverted_key:6(geometry!null) + │ ├── inverted constraint: /6/1 + │ │ └── spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── stats: [rows=307.105263, distinct(1)=87.7443609, null(1)=0, distinct(3)=2, null(3)=0, distinct(6)=3, null(6)=0, distinct(3,6)=6, null(3,6)=0] + │ │ histogram(3)= 0 100 0 100 + │ │ <--- 'banana' --- 'cherry' + │ │ histogram(6)= 0 0 51.184 0 51.184 102.37 51.184 0 0 0 51.184 0 + │ │ <--- '\x42fd1000000000000000' -------- '\x42fd1000000000000001' -------- '\x42fd1000000100000000' -------- '\x42fd1200000000000000' --- '\x42fd1400000000000000' -------- '\x42fd1400000000000001' + │ ├── key: (1) + │ └── fd: (1)-->(6) + └── filters + └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool, outer=(2), immutable, constraints=(/2: (/NULL - ])] + +opt +SELECT k FROM spatial WHERE st_intersects('LINESTRING(0.5 0.5, 0.7 0.7)', g) AND s = 'banana' +---- +project + ├── columns: k:1(int!null) + ├── immutable + ├── stats: [rows=11.1111111] + ├── key: (1) + └── select + ├── columns: k:1(int!null) g:2(geometry!null) s:3(string!null) + ├── immutable + ├── stats: [rows=11.1111111, distinct(2)=7, null(2)=0, distinct(3)=2, null(3)=0] + │ histogram(3)= 0 11.111 + │ <--- 'banana' + ├── key: (1) + ├── fd: ()-->(3), (1)-->(2) + ├── index-join spatial + │ ├── columns: k:1(int!null) g:2(geometry) s:3(string) + │ ├── stats: [rows=307.105263] + │ ├── key: (1) + │ ├── fd: (1)-->(2,3) + │ └── inverted-filter + │ ├── columns: k:1(int!null) + │ ├── inverted expression: /6 + │ │ ├── tight: false + │ │ └── union spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── pre-filterer expression + │ │ └── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool] + │ ├── stats: [rows=307.105263] + │ ├── key: (1) + │ └── scan spatial@p,partial + │ ├── columns: k:1(int!null) g_inverted_key:6(geometry!null) + │ ├── inverted constraint: /6/1 + │ │ └── spans + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x10\x00\x00\x00\x00\x00\x00\x00"] + │ │ ├── ["B\xfd\x10\x00\x00\x00\x00\x00\x00\x01", "B\xfd\x12\x00\x00\x00\x00\x00\x00\x00") + │ │ └── ["B\xfd\x14\x00\x00\x00\x00\x00\x00\x00", "B\xfd\x14\x00\x00\x00\x00\x00\x00\x00"] + │ ├── stats: [rows=307.105263, distinct(1)=87.7443609, null(1)=0, distinct(3)=2, null(3)=0, distinct(6)=3, null(6)=0, distinct(3,6)=6, null(3,6)=0] + │ │ histogram(3)= 0 100 0 100 + │ │ <--- 'banana' --- 'cherry' + │ │ histogram(6)= 0 0 51.184 0 51.184 102.37 51.184 0 0 0 51.184 0 + │ │ <--- '\x42fd1000000000000000' -------- '\x42fd1000000000000001' -------- '\x42fd1000000100000000' -------- '\x42fd1200000000000000' --- '\x42fd1400000000000000' -------- '\x42fd1400000000000001' + │ ├── key: (1) + │ └── fd: (1)-->(6) + └── filters + ├── st_intersects('010200000002000000000000000000E03F000000000000E03F666666666666E63F666666666666E63F', g:2) [type=bool, outer=(2), immutable, constraints=(/2: (/NULL - ])] + └── s:3 = 'banana' [type=bool, outer=(3), constraints=(/3: [/'banana' - /'banana']; tight), fd=()-->(3)] diff --git a/pkg/sql/opt/xform/testdata/external/postgis-tutorial-idx b/pkg/sql/opt/xform/testdata/external/postgis-tutorial-idx index e49cc8277ca9..455fd8e4ed71 100644 --- a/pkg/sql/opt/xform/testdata/external/postgis-tutorial-idx +++ b/pkg/sql/opt/xform/testdata/external/postgis-tutorial-idx @@ -22,35 +22,34 @@ WHERE ORDER BY name, boroname ---- -project +sort ├── columns: name:3 boroname:2 ├── immutable ├── ordering: +3,+2 - └── select - ├── columns: boroname:2 name:3 geom:4!null + └── project + ├── columns: boroname:2 name:3 ├── immutable - ├── ordering: +3,+2 - ├── sort - │ ├── columns: boroname:2 name:3 geom:4 - │ ├── ordering: +3,+2 - │ └── index-join nyc_neighborhoods - │ ├── columns: boroname:2 name:3 geom:4 - │ └── inverted-filter - │ ├── columns: gid:1!null - │ ├── inverted expression: /6 - │ │ ├── tight: false - │ │ └── union spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] - │ ├── pre-filterer expression - │ │ └── st_intersects('0101000020266900000000000026CF21410000008016315141', geom:4) - │ ├── key: (1) - │ └── scan nyc_neighborhoods@nyc_neighborhoods_geom_idx - │ ├── columns: gid:1!null geom_inverted_key:6!null - │ ├── inverted constraint: /6/1 - │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] - │ ├── key: (1) - │ └── fd: (1)-->(6) - └── filters - └── st_intersects(geom:4, '0101000020266900000000000026CF21410000008016315141') [outer=(4), immutable, constraints=(/4: (/NULL - ])] + └── select + ├── columns: boroname:2 name:3 geom:4!null + ├── immutable + ├── index-join nyc_neighborhoods + │ ├── columns: boroname:2 name:3 geom:4 + │ └── inverted-filter + │ ├── columns: gid:1!null + │ ├── inverted expression: /6 + │ │ ├── tight: false + │ │ └── union spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] + │ ├── pre-filterer expression + │ │ └── st_intersects('0101000020266900000000000026CF21410000008016315141', geom:4) + │ ├── key: (1) + │ └── scan nyc_neighborhoods@nyc_neighborhoods_geom_idx + │ ├── columns: gid:1!null geom_inverted_key:6!null + │ ├── inverted constraint: /6/1 + │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] + │ ├── key: (1) + │ └── fd: (1)-->(6) + └── filters + └── st_intersects(geom:4, '0101000020266900000000000026CF21410000008016315141') [outer=(4), immutable, constraints=(/4: (/NULL - ])] # 11.6 opt @@ -67,35 +66,34 @@ WHERE ORDER BY name ASC ---- -project +sort ├── columns: name:3 ├── immutable ├── ordering: +3 - └── select - ├── columns: name:3 geom:6!null + └── project + ├── columns: name:3 ├── immutable - ├── ordering: +3 - ├── sort - │ ├── columns: name:3 geom:6 - │ ├── ordering: +3 - │ └── index-join nyc_streets - │ ├── columns: name:3 geom:6 - │ └── inverted-filter - │ ├── columns: gid:1!null - │ ├── inverted expression: /8 - │ │ ├── tight: false - │ │ └── union spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] - │ ├── pre-filterer expression - │ │ └── st_dwithin('0101000020266900000000000026CF21410000008016315141', geom:6, 10.0) - │ ├── key: (1) - │ └── scan nyc_streets@nyc_streets_geom_idx - │ ├── columns: gid:1!null geom_inverted_key:8!null - │ ├── inverted constraint: /8/1 - │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] - │ ├── key: (1) - │ └── fd: (1)-->(8) - └── filters - └── st_dwithin(geom:6, '0101000020266900000000000026CF21410000008016315141', 10.0) [outer=(6), immutable, constraints=(/6: (/NULL - ])] + └── select + ├── columns: name:3 geom:6!null + ├── immutable + ├── index-join nyc_streets + │ ├── columns: name:3 geom:6 + │ └── inverted-filter + │ ├── columns: gid:1!null + │ ├── inverted expression: /8 + │ │ ├── tight: false + │ │ └── union spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] + │ ├── pre-filterer expression + │ │ └── st_dwithin('0101000020266900000000000026CF21410000008016315141', geom:6, 10.0) + │ ├── key: (1) + │ └── scan nyc_streets@nyc_streets_geom_idx + │ ├── columns: gid:1!null geom_inverted_key:8!null + │ ├── inverted constraint: /8/1 + │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] + │ ├── key: (1) + │ └── fd: (1)-->(8) + └── filters + └── st_dwithin(geom:6, '0101000020266900000000000026CF21410000008016315141', 10.0) [outer=(6), immutable, constraints=(/6: (/NULL - ])] # 12.1.2 opt @@ -114,35 +112,34 @@ WHERE ORDER BY name, boroname ---- -project +sort ├── columns: name:3 boroname:2 ├── immutable ├── ordering: +3,+2 - └── select - ├── columns: boroname:2 name:3 geom:4!null + └── project + ├── columns: boroname:2 name:3 ├── immutable - ├── ordering: +3,+2 - ├── sort - │ ├── columns: boroname:2 name:3 geom:4 - │ ├── ordering: +3,+2 - │ └── index-join nyc_neighborhoods - │ ├── columns: boroname:2 name:3 geom:4 - │ └── inverted-filter - │ ├── columns: gid:1!null - │ ├── inverted expression: /6 - │ │ ├── tight: false - │ │ └── union spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] - │ ├── pre-filterer expression - │ │ └── st_intersects('01020000202669000002000000000000003CE8214100000080A22E514100000000E0E8214100000000A62E5141', geom:4) - │ ├── key: (1) - │ └── scan nyc_neighborhoods@nyc_neighborhoods_geom_idx - │ ├── columns: gid:1!null geom_inverted_key:6!null - │ ├── inverted constraint: /6/1 - │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] - │ ├── key: (1) - │ └── fd: (1)-->(6) - └── filters - └── st_intersects(geom:4, '01020000202669000002000000000000003CE8214100000080A22E514100000000E0E8214100000000A62E5141') [outer=(4), immutable, constraints=(/4: (/NULL - ])] + └── select + ├── columns: boroname:2 name:3 geom:4!null + ├── immutable + ├── index-join nyc_neighborhoods + │ ├── columns: boroname:2 name:3 geom:4 + │ └── inverted-filter + │ ├── columns: gid:1!null + │ ├── inverted expression: /6 + │ │ ├── tight: false + │ │ └── union spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] + │ ├── pre-filterer expression + │ │ └── st_intersects('01020000202669000002000000000000003CE8214100000080A22E514100000000E0E8214100000000A62E5141', geom:4) + │ ├── key: (1) + │ └── scan nyc_neighborhoods@nyc_neighborhoods_geom_idx + │ ├── columns: gid:1!null geom_inverted_key:6!null + │ ├── inverted constraint: /6/1 + │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] + │ ├── key: (1) + │ └── fd: (1)-->(6) + └── filters + └── st_intersects(geom:4, '01020000202669000002000000000000003CE8214100000080A22E514100000000E0E8214100000000A62E5141') [outer=(4), immutable, constraints=(/4: (/NULL - ])] # 12.2.3 opt @@ -162,35 +159,34 @@ WHERE ORDER BY name ---- -project +sort ├── columns: name:3 ├── immutable ├── ordering: +3 - └── select - ├── columns: name:3 geom:6!null + └── project + ├── columns: name:3 ├── immutable - ├── ordering: +3 - ├── sort - │ ├── columns: name:3 geom:6 - │ ├── ordering: +3 - │ └── index-join nyc_streets - │ ├── columns: name:3 geom:6 - │ └── inverted-filter - │ ├── columns: gid:1!null - │ ├── inverted expression: /8 - │ │ ├── tight: false - │ │ └── union spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] - │ ├── pre-filterer expression - │ │ └── st_dwithin('01020000202669000002000000000000003CE8214100000080A22E514100000000E0E8214100000000A62E5141', geom:6, 0.1) - │ ├── key: (1) - │ └── scan nyc_streets@nyc_streets_geom_idx - │ ├── columns: gid:1!null geom_inverted_key:8!null - │ ├── inverted constraint: /8/1 - │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] - │ ├── key: (1) - │ └── fd: (1)-->(8) - └── filters - └── st_dwithin(geom:6, '01020000202669000002000000000000003CE8214100000080A22E514100000000E0E8214100000000A62E5141', 0.1) [outer=(6), immutable, constraints=(/6: (/NULL - ])] + └── select + ├── columns: name:3 geom:6!null + ├── immutable + ├── index-join nyc_streets + │ ├── columns: name:3 geom:6 + │ └── inverted-filter + │ ├── columns: gid:1!null + │ ├── inverted expression: /8 + │ │ ├── tight: false + │ │ └── union spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] + │ ├── pre-filterer expression + │ │ └── st_dwithin('01020000202669000002000000000000003CE8214100000080A22E514100000000E0E8214100000000A62E5141', geom:6, 0.1) + │ ├── key: (1) + │ └── scan nyc_streets@nyc_streets_geom_idx + │ ├── columns: gid:1!null geom_inverted_key:8!null + │ ├── inverted constraint: /8/1 + │ │ └── spans: ["B\xfd\xff\xff\xff\xff\xff\xff\xff\xff", "B\xfd\xff\xff\xff\xff\xff\xff\xff\xff"] + │ ├── key: (1) + │ └── fd: (1)-->(8) + └── filters + └── st_dwithin(geom:6, '01020000202669000002000000000000003CE8214100000080A22E514100000000E0E8214100000000A62E5141', 0.1) [outer=(6), immutable, constraints=(/6: (/NULL - ])] # 12.2.4 opt