diff --git a/pkg/sql/logictest/testdata/logic_test/join b/pkg/sql/logictest/testdata/logic_test/join index d58ab562eff1..8be6d58e209f 100644 --- a/pkg/sql/logictest/testdata/logic_test/join +++ b/pkg/sql/logictest/testdata/logic_test/join @@ -1205,3 +1205,15 @@ FROM task AS task0_ WHERE EXISTS ( 11 taskWithPatient1WithValidSite1 5 12 taskWithPatient2WithValidSite1 6 13 taskWithPatient3WithValidSite2 7 + +# Regression test for #106371 - only infer self-join equalities if the original +# equality columns form a key over the *base* table, not just the join inputs. +statement ok +CREATE TABLE t106371 (x INT NOT NULL, y INT NOT NULL); +INSERT INTO t106371 VALUES (1, 1), (1, 2); + +query IIII +SELECT * FROM (SELECT * FROM t106371 ORDER BY y DESC LIMIT 1) a +JOIN (SELECT DISTINCT ON (x) * FROM t106371) b ON a.x = b.x; +---- +1 2 1 1 diff --git a/pkg/sql/opt/memo/logical_props_builder.go b/pkg/sql/opt/memo/logical_props_builder.go index 0bbf8f159617..a4dd8a75c59b 100644 --- a/pkg/sql/opt/memo/logical_props_builder.go +++ b/pkg/sql/opt/memo/logical_props_builder.go @@ -2550,14 +2550,15 @@ func (h *joinPropsHelper) addSelfJoinImpliedFDs(rel *props.Relational) { return } for leftTable, leftTableOrds := range leftTables { + baseTabFDs := MakeTableFuncDep(md, leftTable) for rightTable, rightTableOrds := range rightTables { if md.TableMeta(leftTable).Table.ID() != md.TableMeta(rightTable).Table.ID() { continue } // This is a self-join. If there are equalities between columns at the // same ordinal positions in each (meta) table and those columns form a - // key on each input, *every* pair of columns at the same ordinal position - // is equal. + // key on the base table, *every* pair of columns at the same ordinal + // position is equal. var eqCols opt.ColSet colOrds := leftTableOrds.Intersection(rightTableOrds) for colOrd, ok := colOrds.Next(0); ok; colOrd, ok = colOrds.Next(colOrd + 1) { @@ -2567,8 +2568,7 @@ func (h *joinPropsHelper) addSelfJoinImpliedFDs(rel *props.Relational) { eqCols.Add(rightCol) } } - if !eqCols.Empty() && h.leftProps.FuncDeps.ColsAreStrictKey(eqCols) && - h.rightProps.FuncDeps.ColsAreStrictKey(eqCols) { + if !eqCols.Empty() && baseTabFDs.ColsAreStrictKey(eqCols) { // Add equalities between each pair of columns at the same ordinal // position, ignoring those that aren't part of the output. for colOrd, ok := colOrds.Next(0); ok; colOrd, ok = colOrds.Next(colOrd + 1) { diff --git a/pkg/sql/opt/memo/testdata/logprops/join b/pkg/sql/opt/memo/testdata/logprops/join index 637c2c0dd3d5..d7c0b4116ed8 100644 --- a/pkg/sql/opt/memo/testdata/logprops/join +++ b/pkg/sql/opt/memo/testdata/logprops/join @@ -2951,8 +2951,10 @@ inner-join (hash) ├── variable: xyz.x:1 [type=int] └── variable: foo.x:6 [type=int] -# Self-join filters can be inferred even if the join key wasn't a key in the +# Self-join filters can only be inferred even if the join key was a key in the # base table. +# TODO(drewk): if the optimizer could see that the same row is being selected +# from each input, we could still infer equalities. norm SELECT * FROM xyz INNER JOIN xyz foo ON xyz.x = foo.x AND xyz.y = 1 AND foo.y = 1 ---- @@ -2960,7 +2962,7 @@ inner-join (hash) ├── columns: x:1(int!null) y:2(int!null) z:3(int) x:6(int!null) y:7(int!null) z:8(int) ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-one) ├── key: (6) - ├── fd: ()-->(2,7), (1)-->(3), (6)-->(8), (1)==(6), (6)==(1), (2)==(7), (7)==(2), (3)==(8), (8)==(3) + ├── fd: ()-->(2,7), (1)-->(3), (6)-->(8), (1)==(6), (6)==(1) ├── prune: (3,8) ├── interesting orderings: (+1 opt(2)) (+6 opt(7)) ├── select @@ -3002,8 +3004,8 @@ inner-join (hash) ├── variable: xyz.x:1 [type=int] └── variable: foo.x:6 [type=int] -# The optimizer doesn't detect the contradiction here because the "y" filters -# pushed down before the join properties are calculated. +# Self-join filters cannot be inferred here because different rows are selected +# from each input. norm SELECT * FROM xyz INNER JOIN xyz foo ON xyz.x = foo.x AND xyz.y = 1 AND foo.y = 2 ---- @@ -3011,7 +3013,7 @@ inner-join (hash) ├── columns: x:1(int!null) y:2(int!null) z:3(int) x:6(int!null) y:7(int!null) z:8(int) ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-one) ├── key: (6) - ├── fd: ()-->(2,7), (1)-->(3), (6)-->(8), (1)==(6), (6)==(1), (2)==(7), (7)==(2), (3)==(8), (8)==(3) + ├── fd: ()-->(2,7), (1)-->(3), (6)-->(8), (1)==(6), (6)==(1) ├── prune: (3,8) ├── interesting orderings: (+1 opt(2)) (+6 opt(7)) ├── select diff --git a/pkg/sql/opt/norm/testdata/rules/combo b/pkg/sql/opt/norm/testdata/rules/combo index e4ab57e43110..40daf9848844 100644 --- a/pkg/sql/opt/norm/testdata/rules/combo +++ b/pkg/sql/opt/norm/testdata/rules/combo @@ -489,7 +489,7 @@ INNER JOIN a a3 ON a2.k = a3.k INNER JOIN a a4 ON a3.k = a4.k INNER JOIN a a5 ON a4.k = a5.k ---- -https://raduberinde.github.io/optsteps.html#eJzsXV1z20Z3vu-v2OpKKgFaAEiJ4juaceo4U3lU2bX89ib2ZBCJrGFTpEtSadxOM5n8Bl_m1-WXvINvENiPs4sFsIBObmIB2OXifOyefc5zFv93dPsf10fzo9uX1y9fvCP_Qn54-_rfiU985_366ubm5Vvy6vXVTXjBJa9viO-MP5PL6H_l-150343ve9X7k-i-F9-fVO9Po_uT-P50_PnIOrrZbB--D5bLo_mRbdvEf3a1DvaBv3q_Ho1G5Of8z-fPie2QkWNNXfL8-fv16Mt282lxt3-_HpG_vv3517ff__r2O7nbrB4f1rs5-Tx3_nn9uFqRYO6S5dwju_mEfJpPyef5LL1xQZZz55Ts5o5DPs0dN2w0TW86Z-Hd8_DuLLx7QT7PXTfr0yPLuTshu7k7JZ_m7ll49yK9652GP-mQ3dxzyae55x0O8vPi65wcO5Z7cXJ4Y3kfXj-x7fePp6fe4ti1pycWOfasyclvvyXXHMu1oquz_LkL23HDS86p5Tj5ozPrwnJcy5nazoXlurZ7ZrkXtudFj07z5s6Z7VxEF88tZ1Zob0etLefMqnYwO7m8PHamluuG7xH3eHl5PMsvuG7hTTzbPYsuTix3WvmJeICW61nFn3DduMfwV-IeL_IevdPkKc-xPJfRYzxiyzu1kh4v8h7dRPjfEuEH6_Via3_aBGty_NHffYxuR_9RzCv0jtTCfGccGpnvjEM7851xaGq-Mw6tzXfGd9v7n38K1vvFdu2vfnr45e7up33wsNjt_Ycv87Pwib3_82qxCe7n55FzpQbqu-PQRn13HJmp744jS_XdcWSsvsvv2vHCR7K-nUnkmZmF-944MnLfG0d27nvjyNR9bxxZu-_xu3dPw0ey7l0ncuzMRfzJOPISfzKOHMWfjCNf8SfjyF38iaD78_CRvPtZNGFkPuZPx5Gb-dNx5Gn-dBw5mz8dh_4W_p_bvTcJH8m696YUZT88rvbBl1VwF-y_zslqsdzb283_7I4Xv_p3-9VXe7NenFhkG_zXx-TG_y62G3uztR822wXNekp-X7pbdf5zuvPH1w_df8J0__Teob-7DsXfU1dP7sp7-Izi4albp3dFPj2l-HTqwsndqheXRMlz5T_Qow3xaLZStHneHwwHdDkPGeyHh05Y2wM5QgB4EDoS2JGEwtNt8Ay7p6q8J-ZfsH3xSxTN92672e3YTYZkxtCXTO2BI8n2rAI6hN2dvyY--dHfXfrOB1GrltUqOZxEAcJ3T_73TUELKmJ11cXaoVVTZSs2bZpsddpt1nGw2i-2O_7j5LBNbKUJCjN3yI-bx_1ie3kcToh3m_Vuv_WD9X53efzMmZPjZzd_v74mNvlwwtYfTd2eUN1VPXezTtLdh7OaUR1Hcu1hdg7TbFmlkYckwNncmWY6jSKxslpnRbX-jTxzpgd6tsjy_pK2MlI0StP8RGwoucpb3gRQdU2N2GlKlg2Iq70KtFtWa6LNy1ROua8mEXvJX6clzbouRbOxOrMQP1bzB8pOt6jUKUf5uTbbQlHoarzgCfx-Lg8HFLpjKa6ssURPl6ksMo2luMahxg4VFGrsgqKxWEsZpBFr78P7dQxq3wYPX1bB8uut_7D4T3_78r8f_VWwDxa7FObmPBAB39bULWDfJMO-qTo2DfumbsFDS-BHmIh9N4p9Ez72TcpTTa93Rv1GyhqftSvKrgtIVDos-X3prqmgg_nYd0WUPFceEtbRb49mK0Wb5_Gwb9ZDBvuhfuybJQSAB6EjSezpBcLTbfA87FvwrKnmf4h9C16Chn0zmgzJjKEvWcS-YS0axb5hQyhj3_xWrWPfUsPJsW9QMzXsW16srrpYO7RqJvYtL1uddluBYmzO4-SwjX7sm_Yrx0nvV7fk-6vbd1c3L97FvMgX392-O446_e6WXN28m52ckNdvDy__6-vX1yfQgf2N7MO164RtXyxsXnbW7mYdZ2PzQBtRw-YZnVcsj_pc2eTawubLg2Fh8wJDaQ2bF4yjgM2L1KGGzZd7FWi3rNZWsfns51nYPEv5rWHzrAEUsHmmwNWw-YpKyoora6xDbP7VJlj_kKUODlD5g1uIxyMej3i82aAD4vGIxyMejx6NeDzi8ehIiMcjHo94POLxiMcjHi-Px3eClMtz5QHDQ8SeNwEgYo-IPSL2iNgTvuLKGusAsX_zuPsYw_FX6_3m1SZYXy-W-xS0Z909wO3PEbdH3B5xe9PACcTtEbdH3B49GnF7xO3RkRC3R9wecXsY_skDNFXPkMlaLVbJJpH3dF9Qfr6kaqH8Uue0NNi10lFBretPZVSSBwc1r02pU27MAfAx8cQ2EJ0Tr4ZCkGbsQursJnK83z4CYiRMB2E6CNNBmA7CdFCb6aC3i4fNL4ubzf7mcbV6sVnfB_tgs07TQay7STroPEoHnWE6CNNBmA4yDfPCdBCmgzAdhB6N6SBMB6EjYToI00GYDtJaxjGoxI5UM53lG4LsC6ixmUKuJ-ta2Re5NB0EXjcOZVcD2zF1w7auBmuGMAci9m3MgWAOBHMgmANpPwfychU8BGt_v7hNQto4-VG5nGQ9zqKsh4NZD8x6YNbDNGgHsx6Y9cCsB3o0Zj0w64GOhFkPzHpg1kNrEUy6RYQ9PcijrkDoulquRKrrsnRBjVsXssqoJGXdeq4kw7Mb_AI3bErADAZmMDCDgRkMzGBgBuPpZjCuF8v9d7vd5i7w94tXm2C9exvu0tJMBvN2ktFwBpjRsDGj0V1GY6RJ-FYuQjUVlDrRqofonZ1I-s5Z-O9koNHl8_j3on-fRv92on9H64UTdx4HCPH0G7eNu6RiagZqmWDeqi8o99DyVnb5rqmAofl5q9EARNnsVOx4UbwVtXXjPuOFZhJdj9q6cZ8TgxRb8SBMSPZhqu44IVmGA3swK-hPSLKEQPGgMgLaS3kNaP7kqEQiH4fzIARNZaQOusgnC4Ziqjce5pMFL0GzX1jWstdmDH3JYj4Z1sKEfLJKDtOw5KUJxyT2ydHNWnCFIlU797PrIyBlD31sxBoB8WKHmenG4wPYu0qHCcUbkmZACw85EwlOD0jEaJ6IIXUKaEbEEASLZSKGbKDYzdaB7bVAIakRMRidwyrEyeHDrREx5CmIHrSqvHVzkBoVeC7XYxxSp93KfX2xY1OBcryQ4oMUH6T4IMVnoBQfZJmYzDLRyyWysresretCV01o3HK9gtLTvxK9W-6kqPr0z0T7ofoKBpD-mdiAlQw6MYPkz6Il0N6xnlF48Us4SVfJqGP7dafJMGOzdc-ScTnIWjId4kHW0pNjLRkETZlDtakolgf89l_5LS9NqVFY7nnRLpI_U9OwEvUm1mFl2q5vIDVWr_N0rLFJz9LBOZosr2JVEJIDLm2dL21sjhGyvJ4mawnCOROwPtCvNbCWhkYrMstRpPJWYkKMKUwYWQqMHraB6WbIm7WfSgzZXADJtgcgY6dzqg6Yo6PXXeCsnCHRcRoPaAUybIbmQ8nxQRiCOAUOZAos73bErs5oMUCPh75rTc-E_Qj4TBUk4CEBr2UCnryAxUcbdcWkUhAxwCn1MKn4vwE79qhjJhWMKcgkabKYVGBAp2VQkh1liQShxqQq9ypgYJatoFUmlUTZxEShbKKbaF06rNajdxhBkfGcUVYg5FQi7w55d1T9PlHeHTKynjojy-YzspogAFrZwDUZXaHDhkzP8k4PrS-9kBug5TklG0yv5GYYqunQEtMruTEmeirYo5WZEUACmgwzeb-CbSZvUzDPZOwFC81tDDBSdasNG59mI3WT3vKRxu7vuflIY5f3vHyk7lli3TTjr3A3MLnbOcbdeAhW4ZEhH9HMtRkpaYpkSBaDBWe3zmc3tlIGSx17KrNGc1MGDOLkEHk6Z_CAqTs1SQg98JN-bEIKXmR5k5IjJVcKvmQlq1TuTukVretwvd1K7mDpK-U-ZmXLbL2VWdOWJbwyyYcbz13eNB_uIaAL5SR1R0YSs5A0eb7E6ZFDoB_0fTPG0o1mIhMFZufyPHFBwAWhhwsCK7tU5xufODeqHonSDOULfuAKkjGHuBUUKBvJmIB3RTImkjGRjCklYCRjPlEypmC9AR5X1xUDT2aq5sVSehh4jM7VvkXaKgNPwBmtcnFZDDxxTqqt9C8bGmC-rBoDzy6rrky0LWu2VQYepL5xKlPf2DJiBEd49GhTwEUtP2CGbpnuGtEv32wf1xGv8nqx3L_YrHYp8ZJyY8CUy0osjhw45MANhgNHBBy4ysqNLJEnkHZRVzYqz5gDFQfMNzRhMcLUVw9SXwAKEDiCQ6NHo--F0VdWAhEfsHsCkOwvC89aFOE1yicZsXthTSS6PgeNoVXnoVWzCUNA1S_SkXB5GszyhHQkpCMhHQnpSEhHatEzkY6EdCSkIyEdCelIEsaBdKRe0JHKI4Ke99UVaUUwDg4OoIe0Uu5V8uOprZJWKj8vIK1EZ4FRWSuFOwe0lSnSVqpJD6StIG3ladJW-rvB7Dvc3i4NRUoVUoKVEJMG-gbmsTFRMKxEgU7yBsYxGMcYGccQ9lbVAR1NrY8wwdwOSlAdIJ_jFdNPMPbq_BhMvcmIylSe7bK1HsNjWiwHLyZDYgfGa32P1yCf0WUsAbgSaP9gTM0Zu_bnaJDYMURih0DZcFcfoMdD37UZz2TnkGENkNhxyf9MtoDYwW_VDbFDakw5sQPUrAaxQ17AnrqAO3V5VafUQ-wAfgid_oE3M4gdEp-s53zMrytih8xUzYul9BA7YB9QZDxXNoBOz5mBHiPTFbEDFjzTcAA9xI6a33I04qQZyrqCID6C-AaC-KwSQeGh44Q1PfV3D9R3_JurIK3HjxPmmsB9DgFiBIj7ChBzDRs6Ww4QOGp8HwIRZBOTG3ujA3kckeMhIccQjUvOAQOcCqReuEGXZQNXEq0QUk4hZQmhlXFlQNNuwGX5geUIM7xtDZhZUeheTaF3Pz_Ucl490DPgh2BH5JoAQkOWrjISrbRudRgGqoVqeoBp3i9IWEnZPFqFqLl7G_6p2XSD6ujobPpgROiEHtiae0Y2zwDKmjexMvHlKngI1v4-qkH8-_p-sX0TcyCvF8t9WqQoeCipV5xG9YqnfaxXtNkVLsjzNwRLwxRBAykCitm7pRto9mj2ULPvoqi2EtY8hbrMSkFLY3WZ6MNPzIf7snSxHMDFGk10APMWMc7eu48VlZUXyjZ8WusoTVtu4ZQ5JIzhjNKvJZVFzxRWzzDj7_4mPPtOGOMqSGulDzUMo8yItIAMCWPlaQ0JYz0gjHENGzpbDpAl0nLhCl2QTUxu0MoYcASIhLHeEsYgGpecAwY4FUi9cIMuy-acSLRCwtgltQaZKzR-ITK1aTeEMfmBsUqSeW211SWDhV4tTpYTevfzQy3n1UMYA_wQrIrRBMIYZOnily5zja-j-mXumIChmh7CGO8XJKykbB4d1jQTtnFUC5vpBtVRdTN9MCJ0Qg9hjFvGzDOAsuaNqHhWVKABID_7nZg8UsTtEbdvtywbXGQ0yH1iy-Ry3VtPQe-caQYxogFjRAJlw119gB4PfddmPJO9pYQ1QCjoklo7CEWB-K26AYCkxsQqFtQP-8gLuFoiaArYoyBigFPqgXj4vyGo8zED2BGsN_wiwM7hHJmpmhdL6QFxGJ3D7KBsAB3W-uWjSJh5wWbNqlP889BgY3wn2uxbJDVZYTVhMjEnjYO5d5o1voA0jqbzpPVy7jlZa-cU0jxaBZLmu7nn5s0dZvOCo0aLR9L809zz8uYdVdOdkpFjTSaDqaZzsZoOcRijcJiqkSYxBxqpKUbaEMerEVPFSjXJSjUXK9XM8zhcFhjmergfRXM1w1z7tkAQ9s78qVWB9S-bLKgCo52Uj9lkXK66yCYruplUGNiMT4pIG1RcGN0Ml1nKMivOu-IX_xqnWAxBhlWb0putxs8aniCP5ERQa1RjPhukS7byWUMQw4uXq0bmCJA5okYZMYorIksS0c8OUaOFtM4HYaymbOfCj4Xix0KlHA8_FoofCzWEnYUfC2WZgzZ2lh5bY6xKPfgSKYiM1pa9l8VI5aEdPkQOrUnEQxM15vLQRI0FPDRRcwEPjf-JUyEPTcSCq9k8k3pss4rsv3gSUmX_xVOXMvsvnvGU2X_xRNk1-28yISPH8mZDYf8l4QLmzRHQVwH0aVy9mUlUvYr-KwKu6L8i8ar-qzqo6r-qlar-W9ITzeyrVl616aoFH9orEuvkiHWHezMj_ANn3N7NuAzjmhnHgsO5t-G5t6Rs5Kz1iUzD56xRYTwk0-BKkK8ELOt4mmQa4Uu2QQThge-YCgOmwtRyYEYlv2SzXvrTXWp5LsMSXNKZrWZSWmpphq6OGGgzNpKyDrA_iojGtHRTo6ERbmQa3ciwdAnkG5lBNAIzjGrM9aTUI-bvCpkkUXPoORIqCTiw2GgJOLjYqAk4uNioCTh42pOagIOnPZWaZ1KPVxrFtGe8MqmmPeP1TDntGS-DymnPePVUS3u-2T6uF7d3_vrFZrVL05yli3Fa05v1N63JAkONyWpi-NBw-KBHz0ytog4xj9hFHrHy0oezW-kmTnHDdQ-teT2c5zBn10LOTvwm_cOl-DKl4byIS_XXWWUwRpxUDZhU1RJIZuGHCqMQ1sAL01D6yx05PXJ8BSFOhDj1Q5xwsfFrDFQwSrDYaBglXGxUjBIuNipGSW2uHaPMqi7epIFjqRoju36AVMbHL9tZtDmiowY9hi9xu9f_yMQWwFoVEOcpwFpMerx2WAtNv0vTLymyjHSIOb1QpEPApKWEvSpIR-WFjGAnN4V08GUqi3SgIxrgiK3vjoGkWbV9KXcXyfL3g10k94O6ol2kqDF3FylqLNhFipqrFLrDd5FgsdF2kWCx0XaRcLFRd5FwscGJMvBdJFhstF0kWGy0XSRcbNRdJFxs1F0knF9E3UXa5SblXeSIE2KMdEQXlE7ywGJUL6YY0cIJ7qj7F0kw5Tc7od7E-MGs-IGioioxV2vUwO6Oajg1YwWKC5e-y6YWIXDaCb7GphoXcFoKv8GmGg1ApEM_skYtBgBJh3FQjerKD5IOg96qymxVJbWq81nVqayqa_uIs6wfWUcvf_2y2mwX3wfL5dH8KEaL3y422_vF9tUmWGeE1sNrCUo8KaDEDEYZYsO4rnaMDbOxMS2wGBcRq0n7oTJ-BhW4cuMPBL6MdzAA5qUZ7oIgXfpALhG-pQptqaJa6oCWOpalDmOpIliq4JU6bqUOWamjVapAlSpGpQ5PqSNT6qBUrzEnHpgWB9n_tgl2-4R28cN283AVhs9heJ1G3JwHKOG3TQu_R8OoMcNAvP9xQq8DcZuekB5UIM6U3-yEehMDcbMcrLhcUteC-k6mJyORn11LsyjtU7sQW3eA2LpCWAGJLmoGGUPee1Fm7RK3QJVWoMooUCcTqPMI1CkEquwBVeKAOmdAnS6gzhRQJQmo8gPUqQHqrAB1QgCfC1B2bMojjDSfpKvSGggSe9LOSWsiTOVJuyP31bnfm4Bn7aQ9j__q_G9JyCToJJ2M--rcc2ZkcnHS_jRScKQaCTXcvOPewoy9BRHsLTTEzXqSRrnJmbG36D1vR7DFcIBbDPhxCuK9k2B_IQHpCBRn61UcuzsqzqI_b1WO0pj7Km5QzK32hWexpKM0fvzLr-SVSVhJRmncV-dW6crkpqSjNP6r8ytw4WkoySiN_-r86lqZjJN0lHb0___0jwAAAP__VSsNvg== +https://raduberinde.github.io/optsteps.html#eJzsXd1y2ziWvt-nwPrKXlFqEZRsSVOu6t50utYpr5ONM3sz6epiO_I2E1nKSvLs9G7t1NQ8Qy776fpJpvgjiQTxcwCBJKCc3LhCEhSJc86Hg_N9AP_v7P4_bs9mZ_cvb1--eEf-hfzw9vW_k5jE4fvlzd3dy7fk1eubu_QAJa_vSBwOPpHr7A97PsrO0_x8VD8_ys5H-flR_fw4Oz_Kz48Hn86Cs7vV-un75PHxbHbW7_dJ_M3NMtkm8eL9stfrkZ8P__32W9IPSS8MxpR8--37Ze_zevVx_rB9v-yR37_89vuXv_3-5W_kYbV4flpuZuTTLPzn5fNiQZIZJY-ziGxmI_JxNiafZpPdiSl5nIVDspmFIfk4C2naaLw7GV6mZ6_Ss5P07JR8mlG6v2dEHmd0RDYzOiYfZ_QyPTvdnY2G6U-GZDOLKPk4i6LqQ36a_zoj52FApxfVE48f0uMX_f775-Ewmp_T_vgiIOdRMLr461-LY2FAg-zo5HDdtB_SILzsh9OARn16GUTDfhSlF4XDIAwPjSfBNEgvHWeX0vRSOt1dOgbd8CoIJ6UbZheOg_AyqN9xcnF9fR6OA0rTV81_4vr6fHI4MM2uuAxoFETD7IrL9Mi0dGCYXXIV0FEQhfkTZEeGpSNhdmQS0HEQ0exI_tNh6QjNjkyD9GXyN8l_nB6OUArpAToK6LjWA3mHps9d7gFK8xdOOyF7YRrl7xdeFu9HR8XbhFfF29Bx8ezhpHh2elk8aTjdPekU8qRRmN6A_6S5oYJoeLjj_kmzH42G-yelxd0OT0pH2RF6eFKae2p0eFJ6WXj3l8K7k-Vyvu5_XCVLcv5LvPklO53948RvCj-7EI7DQRrFcThIAzkOB2ksx-EgDec4HDysP_z8U7LcztfLePHT058fHn7aJk_zzTZ--jy7TK_Yxj8v5qvkw-wqQ68dAsR0kIJATAcZDsR0kEFBTAcZGsRUfuswSi_Z3zscZdC3h5A4GmQoEkeDDEjiaJBhSRwNMjiJI_nt6TC9ZH97GmbIucegeDTIYCgeDTIkikeDDIzi0SDDo3ikuP1Vesnh9pMMkfcgFo8HGY7F40EGZfF4kKFZPB6kgJb-ld4-GqWX7G8fjTnGfnpebJPPi-Qh2f46I4v547a_Xv3P5nz-l_hhu_i1v1rOLwKyTv7rl-LE_87Xq_5q3X9arec872GAlTlbR9crPrrmx6v4OhKi6e5cCT7Dyz4NOWi5A8rirG_4GGbRTYcBvQqi7KVp_uvR4UiY4RkNAzoJogwTaP7ro9KREs6mkDXhwOoOS3dnmwLSq90LDHevNNk9brh73BLYptg65mDrDkr7-yb20TQ9Mjo8Ls29d3x4XDrhub0Mdv-O6OsI-oqNYg0l_y4ASyq5yGHMrAJmFS2rUMngJAOSDEIy8MhgIwOMDCoykMjgIQOGRyNhFQYZDGQAkEE_BvoY3JP4AwBMEFPAmKLsPNuxL4CAcKy-1lUkKMFACQNKAFCO_nLol-O-HPTliC-HeznWy4FejvJyiKu7tBxMD-vVZiNuckpBBX3JnXdOwN3SoI9CH2HzEC9JTP4Ub67j8EdVq5bNqvk4hQGU7178-WJgBZNupebd2qFXc_tW7dq8vrXpt_sbJ4vtfL2RX06qbXIvLWrFs5D8afW8na-vz1MYfFgtN9t1nCy3m-vzb8IZOf_m7o-3t6RPfrwQ249n7khp7rqduxm1-eEjGVu5gaM5EgpvDrMsa9IsQory_iwc721aJJxVs07KZv0D-SYcV-wckMcP17xxmmNRnuVHakc5mLzl2RnX1typFM_Iunl__a4K67JmLax5veunQ6wWUykmXseMZSnlWDY3Zz73yqcl4bhiW55RxxLjH6zZVimSb8aprMM_zPRLQqXbiQzHWqyw0_WuL_YW2xUHqxarGii12JRjsdxKRQVtWljvx_fLnHq7T54-L5LHX-_jp_l_xuuX__0cL5JtMt_syDjJBRk9F4xpiaEje4aOa2PXGDpubST1BHmGiQwdMnQ-M3REztARFsu9nnr6XSNufFisGfvY-lPthgywMmddrTF5g4_I0HnA0NXcXga7p1T48xt9xUaxhpIyhk50kcOYiQxdgwydyB8AYIKYolHrU3Se7diXMXSKa11FApcZOkWX8hg6QZNTCiroS5YZOliLRhk62COwDJ28VesMndbjHBg6UDMzhk6_W6l5t3bo1UKGTr9vbfptrWDcl1xOqm3sM3S8Xzkv7n5zT76_uX93c_fiXb7G5MV39-_Os5t-d09u7t5NLi7I67fVw__6-vXtBfTB_kC26Uh6IfYvEYOoi9rdZBViBhHoI2YMouDmNc_jXse6XFsMIvswIgZR4SitMYiK5ygxiCpzmDGI7F0V1mXN2iqDuP95EYMoMn5rDKLoAUoMorDDzRjEmklYw7EW65BBfLVKlj_sCc4Kd1g5hawhsobIGiJr6PZ02O-6NbKGyBoia4isIaIvsoY-YCayhsgaeo4pyBoia4isIbKGyBoia-gha9gJn6e_7hDweMgrygAAeUXkFZFXRF6RyA3HWqwDXvHN8-aXnDS8WW5Xr1bJ8nb-uN1Ri6KzFXbxCtlFZBeRXUR20bVps9_1bWQXkV1EdhHZRURfZBd9wExkF5Fd9BxTkF1EdhHZRU_YRRntYrpr6L7VfFGUsmRX-8JFynvqKC5Sa2fOBm9ttDls6_YzeSrNrWKbt6bWvqbu0IxIj4sdxCbwWlhU24xfaO3WS86362dAxoakNZLWSFojaY2kdZuk9dv50-rP87vV9u55sXixWn5ItslquSOtRWcL0voqI60vkbRG0hpJayStXavG-E2bIGmNpDWS1khaI_oiae0DZiJpjaS155iCpDWS1khae0Jawx7htOhnrWY2l8IqOGJQYzc7-bi-Pooj1hMTQEhA57hAM0oQCWaxdzW4_hqZWnVsI1OLTC0ytcjUts_UvlwkT8ky3s7vi5Q2p2hrhwtu9jLjZkPkZpGbRW4WuVnXig5-swPIzSI3i9wscrOIvsjN-oCZyM0iN-s5piA3i9wscrOecLPABcW7Qhbs6pPc3BjEAZoxulq3ZnsX1Lj1TjZ5Ks2-bp3R3bNuekwq7nMNNT3yrMizIs-KPCvyrMizAnjW2_nj9rvNZvWQxNv5q1Wy3LxN54w7vlV4uuBdQ-RdkXdF3hV5VzcLCn5X_pF3Rd4VeVfkXRF9kXf1ATORd22Qd2WLrRIwYUurBqwS4g-kJigogCNHexIcrcK6vGiCMYFeBxX0JcscLayFCxytCS_oGCHowjbOx22i3fV-yro7KDfSdYBxvUNqsvGhFfau2iNs-YSmG4zBDbQZ1ZMdQgVZCTLxYvxocEvtPROvyGxYJl43q-km6xZHLbCTzJh4wc1hGxmQ6sWtMfH6GrQIuvlB6-6g9VRgLLfjHFpbx-t9cL1jV4GKfFDjgRoP1HigxgM1Hqjx4HOYqPFAjYfDpQjUeKDGAzUeqPGQazz6rNvLyrc6fCxCdOcQLebeUQiCQhAnhSAKPhpBxYK6oyK_UFzraqy6zB1pkBRqqt4Vjl6XnLdDLWvS8Z3z8GAC3m73wCn3U-LaG8-eFH3YDIfPKeArrmyXtccsqd1titShLmhxghEPfdcjIxP2I-AV86iuQXWNU_tcmG1c0ZVMwqCLAUFpRyYh_w3YphYdyyRgMiChAkskkwBP4FuugImzLFVHmMkk2Lsq5FWsF7Qqk9DQRI8MNNHdZOvaabUdu8PUR4LrnPICpWAKRTUoquHaF0U1KKpBUU3nopq-XFTTE5yuEbtIvnRek2x8yKzJAVB04xd-oujGd9GNiAJH-O0cfsVGqQhfRBc5DG5I6XQgfAEqATqXAIC5_yNZbSjb3x3Nr-b3LXWBxuY4p0Ds-Z42i2xjWSLAKWCJLmldFIDpMabHtvcdNNY-IDbaW0ncjJgCvk4ZZU6nmBMrjI0yJ8C7oswJZU4oc9LqYJQ5faUyJ8V4A9zlpSttiw5Uy3IpO9oWwc3NvuHUqrZFocaqq9xE2hZ1cb4tok5cGhC-rJm2pc-ajpWwsZZtVdsCWTk01lk51HLFCF7hsWNNhcqLvcAN2wrDNRM2vVk_LzPF0u38cftitdjsJE2cEyhmQjETipk8FDMRhVqpNnIjXf4V0C7mxkbjObO_U2UUq8Wxw-IJPwYjpL48oL5qiHZEBodOj07vhdPXRgKVMKp7AZDuLyu3zFLVa4z3CBHfRQQktj78h6lV56lVs4QhYD0dypFweDqZ4QnlSChHQjkSypFQjtRiZKIcCeVIKEdCORLKkTScA-VIXsiR2CeC7qTTlWhF8RySOoAd0Qp7V81vjrUqWqn9vEK0ku2yw1WtlM5UZCtjlK3USQ-UraBs5euUrfg7wfS93N6uDEXLFFodq9FNFuQbyGMjUXBaRIFN8QbmMZjHOJnHEPFUNQRt-mpPMCGcDmpIHSDfv1PLTzD36nzDQrtkRA3K97Nsq9vwuJbLwReTobAD8zXf8zXIBwkFQwCOBNY_xXAkYh_9oQcUdpyisENhbHion2DEQ9-1mcgUc8iwBijsuJZ_cFQh7JC36kbYofVMB2EHqNkRwg79Do7MO7jTkDcNSjvCDuAnZfmfTnJD2KHx8V_JZ7K6EnboQLUsl7Ij7IB9mkxwHesAne4zA91GpithByx55tUB7Ag7jvxKmhM7zXDGFSziYxHfwSK-aImgctNxIoInf-dAvte_pQayuv04EY4J0uuwQIwFYl8LxFLHhqLlCRaOGp-HQDqyCXATT3Qgl2Pl-JQqxxCLa2LACUKB1gs3GLLiwpVGKywp70rKGp3G1pUBTbspLus_2KHCDG97RJnZsNOjIzu9e3w4KnjtlJ4BPwTbIteFIjRk6JJ_zV_qfB190l_6TMBUzU5hWvYLGl7CukeHn_knYueo75rNd6iOts7mP4yqOmGnbC3dI1vmAKzlXVyZ-HKRPCXLeJutQfzj8sN8_SbXQN7OH7e7RYqKi4r1iuNsveLQx_WKffEKF9T5O1JLQ4qgAYqA4_aUOYFuj24PdfsuFtXW0pqvYV1mbUFLY-syMYa_shj2ZegSBQDFNZoYAO4NYpK5t48rKmsvtJ_wWV1H6dpwC5fMoWAMEcWvIVUkz1SunhHm3_4Snr4LxqQGsrrSh5uGcRCRl5ChYIyFNRSMeSAYkzo2FC1PUCXS8sIVfkc2AW7QlTHgDBAFY94KxiAW18SAE4QCrRduMGTFmhONVigYu-auQZZ2mnwhMrdpN4Ix_QcTLUmWtbW2Lhnc6fXFyXqd3j0-HBW8dgRjgB-CrWJ0QTAGGbrkS5elztfR-mXpMwFTNTuCMdkvaHgJ6x4drmkmYueoL2zmO1RHq5v5D6OqTtgRjEmXMcscgLW8EyueDQ3oQJFf_E5CHSnW7bFu3-6ybPAio5OcJ7YsLrc99VTcXQIzWCM64RqRwtjwUD_BiIe-azORKZ5SwhpgKeiau3YQWgWSt-qmAKT1TKLFgvbLPvodXF8i6Eqxx6CLAUFpp8Qj_w3FOh83CjuK8Ua-CLDzco4OVMtyKTtFHMHNYX7AOkCHa_0OT1Eo85LVUrRO8beqw-b1nWyyH5CdyypXExbAXDROZtFw33gKaZzBedH6cRaF-9bhENI8GwWK5ptZRA_NQ2HzUqBmg0fR_OMsig7NO1pNNyS9MBiNTmY1HcXVdFiHcaoOU3fSIudAJ3XFSRvSeDXiqrhSTXOlGsWVau5FHA4LAnetzkfRXd1wV98GCCKemX9tq8D8Y5MVq8B4O-Ujm4zDVRdssmGYaaWBzcSkSrTBrQtjmOEwyxlm1bwrfvGvcYnFKfRh3afsstX4WcML1JFcKNYaHYFnJxmSrXzWEKTwknHVqBwBKkfMJCNOaUV0RSL21SFmspDW9SCC0VQcXPixUPxYqFbg4cdC8WOhjqiz8GOhInewps6y42uCUcmDL5GCxGht-TvbjVwdWvUiUvUmlQ5N1ViqQ1M1VujQVM0VOjT5J06VOjSVCu7I5vtez33WUP2Xg5Cp-i-HLmP1X454xuq_HCi7Vv-NRqQXBtHkVNR_RbqAvDkW9E0K-jyt3sQlqV7N_rUOrtm_1uN1-9dtULd_3Sp1-7dkJ57b17287tN1D676Kwrr9IR11bmZE_GBiOsd4gqca-KcCg6xt2HsZYyNmjWfxDRyzRq3jIdiGhwJDiOByDu-TjGN8iXbEILIiu9IhQGpMDMOzCnyS5f1sk93mfFcjhFc2sxWM5SWGc3Q1RYDbeZGWt4BjkeV0JhHNzWaGuFEptGJjMiWQL2RG0IjsMLoCKwnzB2RvysxSarm0H0kTAg4cLfxCDh4t3EJOHi3cQk4OO3JJeDgtKdR832v5yONIe2Zj0ymtGc-nhnTnvkwaEx75qOnGe35Zv28nN8_xMsXq8VmR3MyB3NaM5r4S2uKiqHOsJqYPjScPtixs9CqaEPkEbvgEWsvXUU35iRC3OmGh1VeD3EOObsWODv1m_hXl5L3Ka_Oi3Upf4NVp8aIoOoAqJoRSG7VDw2eQrkGXklD2V_uKLmjJFawxIklTvslTni3ydcYmNQowd3Gq1HCu41bo4R3G7dGyW1uvUa5X3XxZpc4Mqsx9scrlcp8--X-Ptvs8asGHpcvcbrnf2bSV5S1akWcr6GsJZTHWy9roet36fqMIdlKh1rTC610KJS0nLTXpNJReyEn1MlNVTrkfapb6cBAdCAQW58dA0WzZvNS6SxSFO-VWaT0g7qqWaSqsXQWqWqsmEWqmpssdIfPIsHdxptFgruNN4uEdxt3FgnvNrhQBj6LBHcbbxYJ7jbeLBLebdxZJLzbuLNIuL6IO4vss03YWWRPkmL0bGQXnJscEovecTlFj5dOSJ_av0xC2H-TC-5JzB_cyh84JqoLc61mDeLbcR3nyFyBE8LMd9nMMgRJO8XX2EzzAklL5TfYTLMBSO_wt6wxywFAvSPYqMZ05Af1jkDeaqpsNRW1mutZzaWspmN7TzKsnwVnL__yebFaz79PHh_PZmd5tfjtfLX-MF-_WiXLvaC1eqyoEo9KVWKBogxrwziudlwbFtfGrJTFpBWxI2U_XMXPSSWu0vwDC1_OBxig5mW53AWpdNkrcqnqW6alLdOqlnlBy7yWZV7GMq1gmRavzOtW5iUr82qVaaHKtEZlXp4yr0yZF6W8rjnJiml5kv1vq2SzLWQXP6xXTzdp-pym17uMW3IBJ_3u89Lv3mmsMcNE3P88wetEvM8npE8qERf23-SCexITcbcCrDxccseC44PMDiNx2LuW51HWoV1ZWw-BtXWDtAKSXRyZZJzy3IuD2oy2wFRWYKooMBcTmOsIzCUEpuoBU-GAuWbAXC5grhQwFQmY6gPMpQHmqgBzQYBcC8AGNucSAc2nGaq8BgpiTzs4eU2UVJ52OEpfXfq9CThrpx158leXf0tCh6DTDDLpq0v3mdHh4rTjqWcQSEcQajh5x7mFG3MLophbWMib7ZBGB5dzY27hvW5HMcUIgVMM-HYK6rmTYn6hUdJRGK5v13Di23HrLPZ5KzZLE86rpEmxdLUvnMXSztLk-a98Ja8OYaWZpUlfXbpKV4eb0s7S5K8uX4ELp6E0szT5q8tX1-owTtpZ2tn__9M_AgAA__9V3MKw # Exploration patterns with varying costs. optsteps diff --git a/pkg/sql/opt/xform/testdata/rules/join_order b/pkg/sql/opt/xform/testdata/rules/join_order index 391b42da23e6..563dbd7ab9ea 100644 --- a/pkg/sql/opt/xform/testdata/rules/join_order +++ b/pkg/sql/opt/xform/testdata/rules/join_order @@ -2948,18 +2948,18 @@ JOIN t88659 AS t4 ON (t3.a) = (t4.b) AND (t2.b) = (t4.a) AND (t2.a) = (t4.a); ---- inner-join (lookup t88659) ├── columns: a:1!null b:2!null c:3!null a:7!null b:8!null c:9!null a:13!null b:14!null c:15!null a:19!null b:20!null c:21 - ├── key columns: [20] = [13] + ├── key columns: [7] = [19] ├── lookup columns are key ├── immutable ├── key: (1) - ├── fd: (1)-->(2,3), (7)-->(9), (7)==(2,8,19), (8)==(2,7,19), (2)==(7,8,19), (13)-->(14,15), (3)==(9,15), (9)==(3,15), (15)==(3,9), (19)-->(20,21), (13)==(20), (20)==(13), (19)==(2,7,8) + ├── fd: (1)-->(2,3), (7)-->(9), (7)==(2,8,13,14,19,20), (8)==(2,7,13,14,19,20), (2)==(7,8,13,14,19,20), (13)-->(15), (3)==(9,15,21), (9)==(3,15,21), (15)==(3,9,21), (19)-->(21), (13)==(2,7,8,14,19,20), (20)==(2,7,8,13,14,19), (19)==(2,7,8,13,14,20), (21)==(3,9,15), (14)==(2,7,8,13,19,20) ├── inner-join (lookup t88659) - │ ├── columns: a:1!null b:2!null c:3!null a:7!null b:8!null c:9!null a:19!null b:20!null c:21 - │ ├── key columns: [7] = [19] + │ ├── columns: a:1!null b:2!null c:3!null a:7!null b:8!null c:9!null a:13!null b:14!null c:15!null + │ ├── key columns: [2] = [13] │ ├── lookup columns are key │ ├── immutable │ ├── key: (1) - │ ├── fd: (1)-->(2,3), (7)-->(9), (7)==(2,8,19,20), (8)==(2,7,19,20), (19)-->(21), (19)==(2,7,8,20), (20)==(2,7,8,19), (9)==(3,21), (21)==(3,9), (2)==(7,8,19,20), (3)==(9,21) + │ ├── fd: (1)-->(2,3), (7)-->(9), (7)==(2,8,13,14), (8)==(2,7,13,14), (13)-->(15), (9)==(3,15), (15)==(3,9), (13)==(2,7,8,14), (14)==(2,7,8,13), (2)==(7,8,13,14), (3)==(9,15) │ ├── inner-join (lookup t88659) │ │ ├── columns: a:1!null b:2!null c:3!null a:7!null b:8!null c:9!null │ │ ├── key columns: [1] = [1] @@ -2988,9 +2988,12 @@ inner-join (lookup t88659) │ │ │ └── filters (true) │ │ └── filters │ │ └── c:3 = c:9 [outer=(3,9), immutable, constraints=(/3: (/NULL - ]; /9: (/NULL - ]), fd=(3)==(9), (9)==(3)] - │ └── filters (true) + │ └── filters + │ ├── c:9 = c:15 [outer=(9,15), immutable, constraints=(/9: (/NULL - ]; /15: (/NULL - ]), fd=(9)==(15), (15)==(9)] + │ └── b:2 = b:14 [outer=(2,14), constraints=(/2: (/NULL - ]; /14: (/NULL - ]), fd=(2)==(14), (14)==(2)] └── filters - └── c:9 = c:15 [outer=(9,15), immutable, constraints=(/9: (/NULL - ]; /15: (/NULL - ]), fd=(9)==(15), (15)==(9)] + ├── a:13 = b:20 [outer=(13,20), constraints=(/13: (/NULL - ]; /20: (/NULL - ]), fd=(13)==(20), (20)==(13)] + └── c:3 = c:21 [outer=(3,21), immutable, constraints=(/3: (/NULL - ]; /21: (/NULL - ]), fd=(3)==(21), (21)==(3)] # Regression test for #90761 - don't drop LeftJoin filter when there are enough # InnerJoin edges to "link" all relations and the LeftJoin doesn't get @@ -3369,3 +3372,76 @@ project │ └── filters │ └── (patient2_.id:11 IS NULL) OR (site3_.id:15 IN (1, 2)) [outer=(11,15)] └── filters (true) + +# Regression test for #106371 - only infer self-join equalities if the original +# equality columns form a key over the *base* table, not just the join inputs. +exec-ddl +CREATE TABLE t106371 (x INT NOT NULL, y INT NOT NULL); +---- + +# Don't add an "a.y = b.y" filter. +reorderjoins +SELECT * FROM (SELECT * FROM t106371 ORDER BY y DESC LIMIT 1) a +JOIN (SELECT DISTINCT ON (x) * FROM t106371) b ON a.x = b.x; +---- +-------------------------------------------------------------------------------- +Join Tree #1 +-------------------------------------------------------------------------------- + inner-join (hash) + ├── limit + │ ├── scan t106371 + │ └── 1 + ├── distinct-on + │ ├── scan t106371 + │ └── aggregations + │ └── first-agg + │ └── y + └── filters + └── x = x +Vertexes + A: + limit + ├── scan t106371 + └── 1 + B: + distinct-on + ├── scan t106371 + └── aggregations + └── first-agg + └── y +Edges + x = x [inner, ses=AB, tes=AB, rules=()] +Joining AB + A B [inner, refs=AB] + B A [inner, refs=AB] +Joins Considered: 2 +================================================================================ +Final Plan +================================================================================ +inner-join (hash) + ├── columns: x:1!null y:2!null x:6!null y:7!null + ├── cardinality: [0 - 1] + ├── multiplicity: left-rows(zero-or-one), right-rows(zero-or-one) + ├── key: () + ├── fd: ()-->(1,2,6,7), (6)==(1), (1)==(6) + ├── distinct-on + │ ├── columns: x:6!null y:7!null + │ ├── grouping columns: x:6!null + │ ├── key: (6) + │ ├── fd: (6)-->(7) + │ ├── scan t106371 + │ │ └── columns: x:6!null y:7!null + │ └── aggregations + │ └── first-agg [as=y:7, outer=(7)] + │ └── y:7 + ├── top-k + │ ├── columns: x:1!null y:2!null + │ ├── internal-ordering: -2 + │ ├── k: 1 + │ ├── cardinality: [0 - 1] + │ ├── key: () + │ ├── fd: ()-->(1,2) + │ └── scan t106371 + │ └── columns: x:1!null y:2!null + └── filters + └── x:1 = x:6 [outer=(1,6), constraints=(/1: (/NULL - ]; /6: (/NULL - ]), fd=(1)==(6), (6)==(1)]