github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/xform/testdata/rules/select (about) 1 exec-ddl 2 CREATE TABLE a 3 ( 4 k INT PRIMARY KEY, 5 u INT, 6 v INT, 7 INDEX u(u) STORING (v), 8 UNIQUE INDEX v(v) STORING (u) 9 ) 10 ---- 11 12 exec-ddl 13 CREATE TABLE b 14 ( 15 k INT PRIMARY KEY, 16 u INT, 17 v INT, 18 j JSONB, 19 INDEX u(u), 20 UNIQUE INDEX v(v), 21 INVERTED INDEX inv_idx(j) 22 ) 23 ---- 24 25 exec-ddl 26 CREATE TABLE c 27 ( 28 k INT PRIMARY KEY, 29 a INT[], 30 u INT, 31 INVERTED INDEX inv_idx(a), 32 INDEX u(u) 33 ) 34 ---- 35 36 exec-ddl 37 CREATE TABLE d 38 ( 39 k INT PRIMARY KEY, 40 u INT, 41 v INT, 42 w INT, 43 INDEX u(u), 44 INDEX v(v) 45 ) 46 ---- 47 48 exec-ddl 49 CREATE TABLE e 50 ( 51 k INT PRIMARY KEY, 52 u INT, 53 v INT, 54 w INT, 55 INDEX uw(u, w), 56 INDEX vw(v, w) 57 ) 58 ---- 59 60 exec-ddl 61 CREATE TABLE f 62 ( 63 k INT, 64 j INT, 65 u INT, 66 v INT, 67 CONSTRAINT pk PRIMARY KEY (k, j), 68 INDEX u(u), 69 INDEX v(v) 70 ) 71 ---- 72 73 exec-ddl 74 CREATE TABLE no_explicit_primary_key 75 ( 76 k INT, 77 u INT, 78 v INT, 79 INDEX u(u), 80 INDEX v(v) 81 ) 82 ---- 83 84 # -------------------------------------------------- 85 # GenerateConstrainedScans 86 # -------------------------------------------------- 87 88 opt 89 SELECT k FROM a WHERE k = 1 90 ---- 91 scan a 92 ├── columns: k:1!null 93 ├── constraint: /1: [/1 - /1] 94 ├── cardinality: [0 - 1] 95 ├── key: () 96 └── fd: ()-->(1) 97 98 memo 99 SELECT k FROM a WHERE k = 1 100 ---- 101 memo (optimized, ~5KB, required=[presentation: k:1]) 102 ├── G1: (select G2 G3) (scan a,cols=(1),constrained) 103 │ └── [presentation: k:1] 104 │ ├── best: (scan a,cols=(1),constrained) 105 │ └── cost: 1.05 106 ├── G2: (scan a,cols=(1)) (scan a@u,cols=(1)) (scan a@v,cols=(1)) 107 │ └── [] 108 │ ├── best: (scan a,cols=(1)) 109 │ └── cost: 1040.02 110 ├── G3: (filters G4) 111 ├── G4: (eq G5 G6) 112 ├── G5: (variable k) 113 └── G6: (const 1) 114 115 opt 116 SELECT k FROM a WHERE v > 1 117 ---- 118 project 119 ├── columns: k:1!null 120 ├── key: (1) 121 └── scan a@v 122 ├── columns: k:1!null v:3!null 123 ├── constraint: /3: [/2 - ] 124 ├── key: (1) 125 └── fd: (1)-->(3), (3)-->(1) 126 127 memo 128 SELECT k FROM a WHERE v > 1 129 ---- 130 memo (optimized, ~6KB, required=[presentation: k:1]) 131 ├── G1: (project G2 G3 k) 132 │ └── [presentation: k:1] 133 │ ├── best: (project G2 G3 k) 134 │ └── cost: 350.17 135 ├── G2: (select G4 G5) (scan a@v,cols=(1,3),constrained) 136 │ └── [] 137 │ ├── best: (scan a@v,cols=(1,3),constrained) 138 │ └── cost: 346.86 139 ├── G3: (projections) 140 ├── G4: (scan a,cols=(1,3)) (scan a@u,cols=(1,3)) (scan a@v,cols=(1,3)) 141 │ └── [] 142 │ ├── best: (scan a,cols=(1,3)) 143 │ └── cost: 1050.02 144 ├── G5: (filters G6) 145 ├── G6: (gt G7 G8) 146 ├── G7: (variable v) 147 └── G8: (const 1) 148 149 opt 150 SELECT k FROM a WHERE u = 1 AND k = 5 151 ---- 152 project 153 ├── columns: k:1!null 154 ├── cardinality: [0 - 1] 155 ├── key: () 156 ├── fd: ()-->(1) 157 └── scan a@u 158 ├── columns: k:1!null u:2!null 159 ├── constraint: /2/1: [/1/5 - /1/5] 160 ├── cardinality: [0 - 1] 161 ├── key: () 162 └── fd: ()-->(1,2) 163 164 memo 165 SELECT k FROM a WHERE u = 1 AND k = 5 166 ---- 167 memo (optimized, ~7KB, required=[presentation: k:1]) 168 ├── G1: (project G2 G3 k) 169 │ └── [presentation: k:1] 170 │ ├── best: (project G2 G3 k) 171 │ └── cost: 1.07 172 ├── G2: (select G4 G5) (select G6 G7) (scan a@u,cols=(1,2),constrained) 173 │ └── [] 174 │ ├── best: (scan a@u,cols=(1,2),constrained) 175 │ └── cost: 1.05 176 ├── G3: (projections) 177 ├── G4: (scan a,cols=(1,2)) (scan a@u,cols=(1,2)) (scan a@v,cols=(1,2)) 178 │ └── [] 179 │ ├── best: (scan a,cols=(1,2)) 180 │ └── cost: 1050.02 181 ├── G5: (filters G8 G9) 182 ├── G6: (scan a,cols=(1,2),constrained) 183 │ └── [] 184 │ ├── best: (scan a,cols=(1,2),constrained) 185 │ └── cost: 1.06 186 ├── G7: (filters G8) 187 ├── G8: (eq G10 G11) 188 ├── G9: (eq G12 G13) 189 ├── G10: (variable u) 190 ├── G11: (const 1) 191 ├── G12: (variable k) 192 └── G13: (const 5) 193 194 # Constraint + remaining filter. 195 opt 196 SELECT k FROM a WHERE u = 1 AND k+u = 1 197 ---- 198 project 199 ├── columns: k:1!null 200 ├── cardinality: [0 - 1] 201 ├── key: () 202 ├── fd: ()-->(1) 203 └── scan a@u 204 ├── columns: k:1!null u:2!null 205 ├── constraint: /2/1: [/1/0 - /1/0] 206 ├── cardinality: [0 - 1] 207 ├── key: () 208 └── fd: ()-->(1,2) 209 210 memo 211 SELECT k FROM a WHERE u = 1 AND k+u = 1 212 ---- 213 memo (optimized, ~8KB, required=[presentation: k:1]) 214 ├── G1: (project G2 G3 k) 215 │ └── [presentation: k:1] 216 │ ├── best: (project G2 G3 k) 217 │ └── cost: 1.07 218 ├── G2: (select G4 G5) (select G6 G7) (scan a@u,cols=(1,2),constrained) 219 │ └── [] 220 │ ├── best: (scan a@u,cols=(1,2),constrained) 221 │ └── cost: 1.05 222 ├── G3: (projections) 223 ├── G4: (scan a,cols=(1,2)) (scan a@u,cols=(1,2)) (scan a@v,cols=(1,2)) 224 │ └── [] 225 │ ├── best: (scan a,cols=(1,2)) 226 │ └── cost: 1050.02 227 ├── G5: (filters G8 G9) 228 ├── G6: (scan a,cols=(1,2),constrained) 229 │ └── [] 230 │ ├── best: (scan a,cols=(1,2),constrained) 231 │ └── cost: 1.06 232 ├── G7: (filters G8) 233 ├── G8: (eq G10 G11) 234 ├── G9: (eq G12 G13) 235 ├── G10: (variable u) 236 ├── G11: (const 1) 237 ├── G12: (variable k) 238 └── G13: (const 0) 239 240 opt 241 SELECT k FROM a WHERE u = 1 AND v = 5 242 ---- 243 project 244 ├── columns: k:1!null 245 ├── cardinality: [0 - 1] 246 ├── key: () 247 ├── fd: ()-->(1) 248 └── select 249 ├── columns: k:1!null u:2!null v:3!null 250 ├── cardinality: [0 - 1] 251 ├── key: () 252 ├── fd: ()-->(1-3) 253 ├── scan a@v 254 │ ├── columns: k:1!null u:2 v:3!null 255 │ ├── constraint: /3: [/5 - /5] 256 │ ├── cardinality: [0 - 1] 257 │ ├── key: () 258 │ └── fd: ()-->(1-3) 259 └── filters 260 └── u:2 = 1 [outer=(2), constraints=(/2: [/1 - /1]; tight), fd=()-->(2)] 261 262 memo 263 SELECT k FROM a WHERE u = 1 AND v = 5 264 ---- 265 memo (optimized, ~6KB, required=[presentation: k:1]) 266 ├── G1: (project G2 G3 k) 267 │ └── [presentation: k:1] 268 │ ├── best: (project G2 G3 k) 269 │ └── cost: 1.11 270 ├── G2: (select G4 G5) (select G6 G7) (select G8 G9) 271 │ └── [] 272 │ ├── best: (select G8 G9) 273 │ └── cost: 1.09 274 ├── G3: (projections) 275 ├── G4: (scan a) (scan a@u) (scan a@v) 276 │ └── [] 277 │ ├── best: (scan a) 278 │ └── cost: 1060.02 279 ├── G5: (filters G10 G11) 280 ├── G6: (scan a@u,constrained) 281 │ └── [] 282 │ ├── best: (scan a@u,constrained) 283 │ └── cost: 10.61 284 ├── G7: (filters G11) 285 ├── G8: (scan a@v,constrained) 286 │ └── [] 287 │ ├── best: (scan a@v,constrained) 288 │ └── cost: 1.07 289 ├── G9: (filters G10) 290 ├── G10: (eq G12 G13) 291 ├── G11: (eq G14 G15) 292 ├── G12: (variable u) 293 ├── G13: (const 1) 294 ├── G14: (variable v) 295 └── G15: (const 5) 296 297 # Only not-null constraint is pushed down. 298 opt 299 SELECT k FROM a WHERE u=v 300 ---- 301 project 302 ├── columns: k:1!null 303 ├── key: (1) 304 └── select 305 ├── columns: k:1!null u:2!null v:3!null 306 ├── key: (1) 307 ├── fd: (1)-->(2,3), (3)-->(1), (2)==(3), (3)==(2) 308 ├── scan a@u 309 │ ├── columns: k:1!null u:2!null v:3 310 │ ├── constraint: /2/1: (/NULL - ] 311 │ ├── key: (1) 312 │ └── fd: (1)-->(2,3), (3)~~>(1,2) 313 └── filters 314 └── u:2 = v:3 [outer=(2,3), constraints=(/2: (/NULL - ]; /3: (/NULL - ]), fd=(2)==(3), (3)==(2)] 315 316 # Don't push constraint into already limited scan. 317 opt 318 SELECT k FROM (SELECT k FROM a ORDER BY u LIMIT 1) a WHERE k = 1 319 ---- 320 project 321 ├── columns: k:1!null 322 ├── cardinality: [0 - 1] 323 ├── key: () 324 ├── fd: ()-->(1) 325 └── select 326 ├── columns: k:1!null u:2 327 ├── cardinality: [0 - 1] 328 ├── key: () 329 ├── fd: ()-->(1,2) 330 ├── scan a@u 331 │ ├── columns: k:1!null u:2 332 │ ├── limit: 1 333 │ ├── key: () 334 │ └── fd: ()-->(1,2) 335 └── filters 336 └── k:1 = 1 [outer=(1), constraints=(/1: [/1 - /1]; tight), fd=()-->(1)] 337 338 # Constraint + index-join, with no remainder filter. 339 opt 340 SELECT * FROM b WHERE v >= 1 AND v <= 10 341 ---- 342 index-join b 343 ├── columns: k:1!null u:2 v:3!null j:4 344 ├── cardinality: [0 - 10] 345 ├── key: (1) 346 ├── fd: (1)-->(2-4), (3)-->(1,2,4) 347 └── scan b@v 348 ├── columns: k:1!null v:3!null 349 ├── constraint: /3: [/1 - /10] 350 ├── cardinality: [0 - 10] 351 ├── key: (1) 352 └── fd: (1)-->(3), (3)-->(1) 353 354 memo 355 SELECT * FROM b WHERE v >= 1 AND v <= 10 356 ---- 357 memo (optimized, ~3KB, required=[presentation: k:1,u:2,v:3,j:4]) 358 ├── G1: (select G2 G3) (index-join G4 b,cols=(1-4)) 359 │ └── [presentation: k:1,u:2,v:3,j:4] 360 │ ├── best: (index-join G4 b,cols=(1-4)) 361 │ └── cost: 51.32 362 ├── G2: (scan b) 363 │ └── [] 364 │ ├── best: (scan b) 365 │ └── cost: 1080.02 366 ├── G3: (filters G5) 367 ├── G4: (scan b@v,cols=(1,3),constrained) 368 │ └── [] 369 │ ├── best: (scan b@v,cols=(1,3),constrained) 370 │ └── cost: 10.41 371 ├── G5: (range G6) 372 ├── G6: (and G7 G8) 373 ├── G7: (ge G9 G10) 374 ├── G8: (le G9 G11) 375 ├── G9: (variable v) 376 ├── G10: (const 1) 377 └── G11: (const 10) 378 379 # Don't choose lookup join if it's not beneficial. 380 opt 381 SELECT * FROM b WHERE v > 1 382 ---- 383 select 384 ├── columns: k:1!null u:2 v:3!null j:4 385 ├── key: (1) 386 ├── fd: (1)-->(2-4), (3)-->(1,2,4) 387 ├── scan b 388 │ ├── columns: k:1!null u:2 v:3 j:4 389 │ ├── key: (1) 390 │ └── fd: (1)-->(2-4), (3)~~>(1,2,4) 391 └── filters 392 └── v:3 > 1 [outer=(3), constraints=(/3: [/2 - ]; tight)] 393 394 opt 395 SELECT * FROM b WHERE v >= 1 AND v <= 10 AND k > 5 396 ---- 397 index-join b 398 ├── columns: k:1!null u:2 v:3!null j:4 399 ├── cardinality: [0 - 10] 400 ├── key: (1) 401 ├── fd: (1)-->(2-4), (3)-->(1,2,4) 402 └── select 403 ├── columns: k:1!null v:3!null 404 ├── cardinality: [0 - 10] 405 ├── key: (1) 406 ├── fd: (1)-->(3), (3)-->(1) 407 ├── scan b@v 408 │ ├── columns: k:1!null v:3!null 409 │ ├── constraint: /3: [/1 - /10] 410 │ ├── cardinality: [0 - 10] 411 │ ├── key: (1) 412 │ └── fd: (1)-->(3), (3)-->(1) 413 └── filters 414 └── k:1 > 5 [outer=(1), constraints=(/1: [/6 - ]; tight)] 415 416 memo 417 SELECT * FROM b WHERE v >= 1 AND v <= 10 AND k > 5 418 ---- 419 memo (optimized, ~6KB, required=[presentation: k:1,u:2,v:3,j:4]) 420 ├── G1: (select G2 G3) (select G4 G5) (index-join G6 b,cols=(1-4)) 421 │ └── [presentation: k:1,u:2,v:3,j:4] 422 │ ├── best: (index-join G6 b,cols=(1-4)) 423 │ └── cost: 24.16 424 ├── G2: (scan b) 425 │ └── [] 426 │ ├── best: (scan b) 427 │ └── cost: 1080.02 428 ├── G3: (filters G7 G8) 429 ├── G4: (scan b,constrained) 430 │ └── [] 431 │ ├── best: (scan b,constrained) 432 │ └── cost: 360.01 433 ├── G5: (filters G7) 434 ├── G6: (select G9 G10) 435 │ └── [] 436 │ ├── best: (select G9 G10) 437 │ └── cost: 10.52 438 ├── G7: (range G11) 439 ├── G8: (gt G12 G13) 440 ├── G9: (scan b@v,cols=(1,3),constrained) 441 │ └── [] 442 │ ├── best: (scan b@v,cols=(1,3),constrained) 443 │ └── cost: 10.41 444 ├── G10: (filters G8) 445 ├── G11: (and G14 G15) 446 ├── G12: (variable k) 447 ├── G13: (const 5) 448 ├── G14: (ge G16 G17) 449 ├── G15: (le G16 G18) 450 ├── G16: (variable v) 451 ├── G17: (const 1) 452 └── G18: (const 10) 453 454 # Ensure the rule doesn't match at all when the first column of the index is 455 # not in the filter (i.e. the @v index is not matched by ConstrainScans). 456 exploretrace rule=GenerateConstrainedScans 457 SELECT k FROM a WHERE u = 1 458 ---- 459 ---- 460 ================================================================================ 461 GenerateConstrainedScans 462 ================================================================================ 463 Source expression: 464 project 465 ├── columns: k:1!null 466 ├── key: (1) 467 └── select 468 ├── columns: k:1!null u:2!null 469 ├── key: (1) 470 ├── fd: ()-->(2) 471 ├── scan a 472 │ ├── columns: k:1!null u:2 473 │ ├── key: (1) 474 │ └── fd: (1)-->(2) 475 └── filters 476 └── u:2 = 1 [outer=(2), constraints=(/2: [/1 - /1]; tight), fd=()-->(2)] 477 478 New expression 1 of 1: 479 project 480 ├── columns: k:1!null 481 ├── key: (1) 482 └── scan a@u 483 ├── columns: k:1!null u:2!null 484 ├── constraint: /2/1: [/1 - /1] 485 ├── key: (1) 486 └── fd: ()-->(2) 487 ---- 488 ---- 489 490 # Constraint + index join + remaining filter. 491 opt 492 SELECT * FROM b WHERE v >= 1 AND v <= 10 AND k+u = 1 493 ---- 494 select 495 ├── columns: k:1!null u:2 v:3!null j:4 496 ├── cardinality: [0 - 10] 497 ├── key: (1) 498 ├── fd: (1)-->(2-4), (3)-->(1,2,4) 499 ├── index-join b 500 │ ├── columns: k:1!null u:2 v:3 j:4 501 │ ├── cardinality: [0 - 10] 502 │ ├── key: (1) 503 │ ├── fd: (1)-->(2-4), (3)-->(1), (3)~~>(1,2,4) 504 │ └── scan b@v 505 │ ├── columns: k:1!null v:3!null 506 │ ├── constraint: /3: [/1 - /10] 507 │ ├── cardinality: [0 - 10] 508 │ ├── key: (1) 509 │ └── fd: (1)-->(3), (3)-->(1) 510 └── filters 511 └── (k:1 + u:2) = 1 [outer=(1,2)] 512 513 memo 514 SELECT * FROM b WHERE v >= 1 AND v <= 10 AND k+u = 1 515 ---- 516 memo (optimized, ~5KB, required=[presentation: k:1,u:2,v:3,j:4]) 517 ├── G1: (select G2 G3) (select G4 G5) 518 │ └── [presentation: k:1,u:2,v:3,j:4] 519 │ ├── best: (select G4 G5) 520 │ └── cost: 51.43 521 ├── G2: (scan b) 522 │ └── [] 523 │ ├── best: (scan b) 524 │ └── cost: 1080.02 525 ├── G3: (filters G6 G7) 526 ├── G4: (index-join G8 b,cols=(1-4)) 527 │ └── [] 528 │ ├── best: (index-join G8 b,cols=(1-4)) 529 │ └── cost: 51.32 530 ├── G5: (filters G7) 531 ├── G6: (range G9) 532 ├── G7: (eq G10 G11) 533 ├── G8: (scan b@v,cols=(1,3),constrained) 534 │ └── [] 535 │ ├── best: (scan b@v,cols=(1,3),constrained) 536 │ └── cost: 10.41 537 ├── G9: (and G12 G13) 538 ├── G10: (plus G14 G15) 539 ├── G11: (const 1) 540 ├── G12: (ge G16 G11) 541 ├── G13: (le G16 G17) 542 ├── G14: (variable k) 543 ├── G15: (variable u) 544 ├── G16: (variable v) 545 └── G17: (const 10) 546 547 opt 548 SELECT * FROM b WHERE v >= 1 AND v <= 10 AND k+u = 1 AND k > 5 549 ---- 550 select 551 ├── columns: k:1!null u:2 v:3!null j:4 552 ├── cardinality: [0 - 10] 553 ├── key: (1) 554 ├── fd: (1)-->(2-4), (3)-->(1,2,4) 555 ├── index-join b 556 │ ├── columns: k:1!null u:2 v:3 j:4 557 │ ├── cardinality: [0 - 10] 558 │ ├── key: (1) 559 │ ├── fd: (1)-->(2-4), (3)-->(1), (3)~~>(1,2,4) 560 │ └── select 561 │ ├── columns: k:1!null v:3!null 562 │ ├── cardinality: [0 - 10] 563 │ ├── key: (1) 564 │ ├── fd: (1)-->(3), (3)-->(1) 565 │ ├── scan b@v 566 │ │ ├── columns: k:1!null v:3!null 567 │ │ ├── constraint: /3: [/1 - /10] 568 │ │ ├── cardinality: [0 - 10] 569 │ │ ├── key: (1) 570 │ │ └── fd: (1)-->(3), (3)-->(1) 571 │ └── filters 572 │ └── k:1 > 5 [outer=(1), constraints=(/1: [/6 - ]; tight)] 573 └── filters 574 └── (k:1 + u:2) = 1 [outer=(1,2)] 575 576 memo 577 SELECT * FROM b WHERE v >= 1 AND v <= 10 AND k+u = 1 AND k > 5 578 ---- 579 memo (optimized, ~7KB, required=[presentation: k:1,u:2,v:3,j:4]) 580 ├── G1: (select G2 G3) (select G4 G5) (select G6 G7) 581 │ └── [presentation: k:1,u:2,v:3,j:4] 582 │ ├── best: (select G6 G7) 583 │ └── cost: 24.21 584 ├── G2: (scan b) 585 │ └── [] 586 │ ├── best: (scan b) 587 │ └── cost: 1080.02 588 ├── G3: (filters G8 G9 G10) 589 ├── G4: (scan b,constrained) 590 │ └── [] 591 │ ├── best: (scan b,constrained) 592 │ └── cost: 360.01 593 ├── G5: (filters G8 G9) 594 ├── G6: (index-join G11 b,cols=(1-4)) 595 │ └── [] 596 │ ├── best: (index-join G11 b,cols=(1-4)) 597 │ └── cost: 24.16 598 ├── G7: (filters G9) 599 ├── G8: (range G12) 600 ├── G9: (eq G13 G14) 601 ├── G10: (gt G15 G16) 602 ├── G11: (select G17 G18) 603 │ └── [] 604 │ ├── best: (select G17 G18) 605 │ └── cost: 10.52 606 ├── G12: (and G19 G20) 607 ├── G13: (plus G15 G21) 608 ├── G14: (const 1) 609 ├── G15: (variable k) 610 ├── G16: (const 5) 611 ├── G17: (scan b@v,cols=(1,3),constrained) 612 │ └── [] 613 │ ├── best: (scan b@v,cols=(1,3),constrained) 614 │ └── cost: 10.41 615 ├── G18: (filters G10) 616 ├── G19: (ge G22 G14) 617 ├── G20: (le G22 G23) 618 ├── G21: (variable u) 619 ├── G22: (variable v) 620 └── G23: (const 10) 621 622 # Constraint + index-join. 623 opt 624 SELECT * FROM b WHERE (u, k, v) > (1, 2, 3) AND (u, k, v) < (8, 9, 10) 625 ---- 626 select 627 ├── columns: k:1!null u:2!null v:3 j:4 628 ├── key: (1) 629 ├── fd: (1)-->(2-4), (3)~~>(1,2,4) 630 ├── index-join b 631 │ ├── columns: k:1!null u:2 v:3 j:4 632 │ ├── key: (1) 633 │ ├── fd: (1)-->(2-4), (3)~~>(1,2,4) 634 │ └── scan b@u 635 │ ├── columns: k:1!null u:2!null 636 │ ├── constraint: /2/1: [/1/2 - /8/9] 637 │ ├── key: (1) 638 │ └── fd: (1)-->(2) 639 └── filters 640 ├── (u:2, k:1, v:3) > (1, 2, 3) [outer=(1-3), constraints=(/2/1/3: [/1/2/4 - ]; tight)] 641 └── (u:2, k:1, v:3) < (8, 9, 10) [outer=(1-3), constraints=(/2/1/3: (/NULL - /8/9/9]; tight)] 642 643 memo 644 SELECT * FROM b WHERE (u, k, v) > (1, 2, 3) AND (u, k, v) < (8, 9, 10) 645 ---- 646 memo (optimized, ~5KB, required=[presentation: k:1,u:2,v:3,j:4]) 647 ├── G1: (select G2 G3) (select G4 G3) 648 │ └── [presentation: k:1,u:2,v:3,j:4] 649 │ ├── best: (select G4 G3) 650 │ └── cost: 411.23 651 ├── G2: (scan b) 652 │ └── [] 653 │ ├── best: (scan b) 654 │ └── cost: 1080.02 655 ├── G3: (filters G5 G6) 656 ├── G4: (index-join G7 b,cols=(1-4)) 657 │ └── [] 658 │ ├── best: (index-join G7 b,cols=(1-4)) 659 │ └── cost: 410.42 660 ├── G5: (gt G8 G9) 661 ├── G6: (lt G8 G10) 662 ├── G7: (scan b@u,cols=(1,2),constrained) 663 │ └── [] 664 │ ├── best: (scan b@u,cols=(1,2),constrained) 665 │ └── cost: 83.21 666 ├── G8: (tuple G11) 667 ├── G9: (tuple G12) 668 ├── G10: (tuple G13) 669 ├── G11: (scalar-list G14 G15 G16) 670 ├── G12: (scalar-list G17 G18 G19) 671 ├── G13: (scalar-list G20 G21 G22) 672 ├── G14: (variable u) 673 ├── G15: (variable k) 674 ├── G16: (variable v) 675 ├── G17: (const 1) 676 ├── G18: (const 2) 677 ├── G19: (const 3) 678 ├── G20: (const 8) 679 ├── G21: (const 9) 680 └── G22: (const 10) 681 682 # GenerateConstrainedScans propagates row-level locking information. 683 opt 684 SELECT k FROM a WHERE k = 1 FOR UPDATE 685 ---- 686 scan a 687 ├── columns: k:1!null 688 ├── constraint: /1: [/1 - /1] 689 ├── locking: for-update 690 ├── cardinality: [0 - 1] 691 ├── volatile, side-effects 692 ├── key: () 693 └── fd: ()-->(1) 694 695 opt 696 SELECT * FROM b WHERE v >= 1 AND v <= 10 FOR UPDATE 697 ---- 698 index-join b 699 ├── columns: k:1!null u:2 v:3!null j:4 700 ├── cardinality: [0 - 10] 701 ├── volatile, side-effects 702 ├── key: (1) 703 ├── fd: (1)-->(2-4), (3)-->(1,2,4) 704 └── scan b@v 705 ├── columns: k:1!null v:3!null 706 ├── constraint: /3: [/1 - /10] 707 ├── locking: for-update 708 ├── cardinality: [0 - 10] 709 ├── volatile, side-effects 710 ├── key: (1) 711 └── fd: (1)-->(3), (3)-->(1) 712 713 opt 714 SELECT * FROM b WHERE v >= 1 AND v <= 10 AND k+u = 1 FOR UPDATE 715 ---- 716 select 717 ├── columns: k:1!null u:2 v:3!null j:4 718 ├── cardinality: [0 - 10] 719 ├── volatile, side-effects 720 ├── key: (1) 721 ├── fd: (1)-->(2-4), (3)-->(1,2,4) 722 ├── index-join b 723 │ ├── columns: k:1!null u:2 v:3 j:4 724 │ ├── cardinality: [0 - 10] 725 │ ├── volatile, side-effects 726 │ ├── key: (1) 727 │ ├── fd: (1)-->(2-4), (3)-->(1), (3)~~>(1,2,4) 728 │ └── scan b@v 729 │ ├── columns: k:1!null v:3!null 730 │ ├── constraint: /3: [/1 - /10] 731 │ ├── locking: for-update 732 │ ├── cardinality: [0 - 10] 733 │ ├── volatile, side-effects 734 │ ├── key: (1) 735 │ └── fd: (1)-->(3), (3)-->(1) 736 └── filters 737 └── (k:1 + u:2) = 1 [outer=(1,2)] 738 739 # -------------------------------------------------- 740 # GenerateInvertedIndexScans 741 # -------------------------------------------------- 742 # TODO(justin): these can be serviced without an index join. 743 # Query only the primary key with no remaining filter. 744 opt 745 SELECT k FROM b WHERE j @> '{"a": "b"}' 746 ---- 747 project 748 ├── columns: k:1!null 749 ├── key: (1) 750 └── index-join b 751 ├── columns: k:1!null j:4 752 ├── key: (1) 753 ├── fd: (1)-->(4) 754 └── scan b@inv_idx 755 ├── columns: k:1!null 756 ├── constraint: /4/1: [/'{"a": "b"}' - /'{"a": "b"}'] 757 └── key: (1) 758 759 memo 760 SELECT k FROM b WHERE j @> '{"a": "b"}' 761 ---- 762 memo (optimized, ~7KB, required=[presentation: k:1]) 763 ├── G1: (project G2 G3 k) 764 │ └── [presentation: k:1] 765 │ ├── best: (project G2 G3 k) 766 │ └── cost: 567.81 767 ├── G2: (select G4 G5) (index-join G6 b,cols=(1,4)) 768 │ └── [] 769 │ ├── best: (index-join G6 b,cols=(1,4)) 770 │ └── cost: 566.69 771 ├── G3: (projections) 772 ├── G4: (scan b,cols=(1,4)) 773 │ └── [] 774 │ ├── best: (scan b,cols=(1,4)) 775 │ └── cost: 1060.02 776 ├── G5: (filters G7) 777 ├── G6: (scan b@inv_idx,cols=(1),constrained) 778 │ └── [] 779 │ ├── best: (scan b@inv_idx,cols=(1),constrained) 780 │ └── cost: 114.45 781 ├── G7: (contains G8 G9) 782 ├── G8: (variable j) 783 └── G9: (const '{"a": "b"}') 784 785 # Query only the primary key with a remaining filter. 2+ paths in containment 786 # query should favor zigzag joins. 787 opt 788 SELECT k FROM b WHERE j @> '{"a": "b", "c": "d"}' 789 ---- 790 project 791 ├── columns: k:1!null 792 ├── key: (1) 793 └── inner-join (lookup b) 794 ├── columns: k:1!null j:4 795 ├── key columns: [1] = [1] 796 ├── lookup columns are key 797 ├── key: (1) 798 ├── fd: (1)-->(4) 799 ├── inner-join (zigzag b@inv_idx b@inv_idx) 800 │ ├── columns: k:1!null 801 │ ├── eq columns: [1] = [1] 802 │ ├── left fixed columns: [4] = ['{"a": "b"}'] 803 │ ├── right fixed columns: [4] = ['{"c": "d"}'] 804 │ └── filters (true) 805 └── filters 806 └── j:4 @> '{"a": "b", "c": "d"}' [outer=(4)] 807 808 # Query requiring an index join with no remaining filter. 809 opt 810 SELECT u, k FROM b WHERE j @> '{"a": "b"}' 811 ---- 812 project 813 ├── columns: u:2 k:1!null 814 ├── key: (1) 815 ├── fd: (1)-->(2) 816 └── index-join b 817 ├── columns: k:1!null u:2 j:4 818 ├── key: (1) 819 ├── fd: (1)-->(2,4) 820 └── scan b@inv_idx 821 ├── columns: k:1!null 822 ├── constraint: /4/1: [/'{"a": "b"}' - /'{"a": "b"}'] 823 └── key: (1) 824 825 opt 826 SELECT j, k FROM b WHERE j @> '{"a": "b"}' 827 ---- 828 index-join b 829 ├── columns: j:4 k:1!null 830 ├── key: (1) 831 ├── fd: (1)-->(4) 832 └── scan b@inv_idx 833 ├── columns: k:1!null 834 ├── constraint: /4/1: [/'{"a": "b"}' - /'{"a": "b"}'] 835 └── key: (1) 836 837 opt 838 SELECT * FROM b WHERE j @> '{"a": "b"}' 839 ---- 840 index-join b 841 ├── columns: k:1!null u:2 v:3 j:4 842 ├── key: (1) 843 ├── fd: (1)-->(2-4), (3)~~>(1,2,4) 844 └── scan b@inv_idx 845 ├── columns: k:1!null 846 ├── constraint: /4/1: [/'{"a": "b"}' - /'{"a": "b"}'] 847 └── key: (1) 848 849 # Query requiring a zigzag join with a remaining filter. 850 # TODO(itsbilal): remove filter from index join if zigzag join covers it. 851 opt 852 SELECT j, k FROM b WHERE j @> '{"a": "b", "c": "d"}' 853 ---- 854 inner-join (lookup b) 855 ├── columns: j:4 k:1!null 856 ├── key columns: [1] = [1] 857 ├── lookup columns are key 858 ├── key: (1) 859 ├── fd: (1)-->(4) 860 ├── inner-join (zigzag b@inv_idx b@inv_idx) 861 │ ├── columns: k:1!null 862 │ ├── eq columns: [1] = [1] 863 │ ├── left fixed columns: [4] = ['{"a": "b"}'] 864 │ ├── right fixed columns: [4] = ['{"c": "d"}'] 865 │ └── filters (true) 866 └── filters 867 └── j:4 @> '{"a": "b", "c": "d"}' [outer=(4)] 868 869 opt 870 SELECT * FROM b WHERE j @> '{"a": {"b": "c", "d": "e"}, "f": "g"}' 871 ---- 872 inner-join (lookup b) 873 ├── columns: k:1!null u:2 v:3 j:4 874 ├── key columns: [1] = [1] 875 ├── lookup columns are key 876 ├── key: (1) 877 ├── fd: (1)-->(2-4), (3)~~>(1,2,4) 878 ├── inner-join (zigzag b@inv_idx b@inv_idx) 879 │ ├── columns: k:1!null 880 │ ├── eq columns: [1] = [1] 881 │ ├── left fixed columns: [4] = ['{"a": {"b": "c"}}'] 882 │ ├── right fixed columns: [4] = ['{"a": {"d": "e"}}'] 883 │ └── filters (true) 884 └── filters 885 └── j:4 @> '{"a": {"b": "c", "d": "e"}, "f": "g"}' [outer=(4)] 886 887 opt 888 SELECT * FROM b WHERE j @> '{}' 889 ---- 890 select 891 ├── columns: k:1!null u:2 v:3 j:4 892 ├── key: (1) 893 ├── fd: (1)-->(2-4), (3)~~>(1,2,4) 894 ├── scan b 895 │ ├── columns: k:1!null u:2 v:3 j:4 896 │ ├── key: (1) 897 │ └── fd: (1)-->(2-4), (3)~~>(1,2,4) 898 └── filters 899 └── j:4 @> '{}' [outer=(4)] 900 901 opt 902 SELECT * FROM b WHERE j @> '[]' 903 ---- 904 select 905 ├── columns: k:1!null u:2 v:3 j:4 906 ├── key: (1) 907 ├── fd: (1)-->(2-4), (3)~~>(1,2,4) 908 ├── scan b 909 │ ├── columns: k:1!null u:2 v:3 j:4 910 │ ├── key: (1) 911 │ └── fd: (1)-->(2-4), (3)~~>(1,2,4) 912 └── filters 913 └── j:4 @> '[]' [outer=(4)] 914 915 opt 916 SELECT * FROM b WHERE j @> '2' 917 ---- 918 index-join b 919 ├── columns: k:1!null u:2 v:3 j:4 920 ├── key: (1) 921 ├── fd: (1)-->(2-4), (3)~~>(1,2,4) 922 └── scan b@inv_idx 923 ├── columns: k:1!null 924 ├── constraint: /4/1 925 │ ├── [/'2' - /'2'] 926 │ └── [/'[2]' - /'[2]'] 927 └── key: (1) 928 929 opt 930 SELECT * FROM b WHERE j @> '[{}]' 931 ---- 932 select 933 ├── columns: k:1!null u:2 v:3 j:4 934 ├── key: (1) 935 ├── fd: (1)-->(2-4), (3)~~>(1,2,4) 936 ├── scan b 937 │ ├── columns: k:1!null u:2 v:3 j:4 938 │ ├── key: (1) 939 │ └── fd: (1)-->(2-4), (3)~~>(1,2,4) 940 └── filters 941 └── j:4 @> '[{}]' [outer=(4)] 942 943 opt 944 SELECT * FROM b WHERE j @> '{"a": {}}' 945 ---- 946 select 947 ├── columns: k:1!null u:2 v:3 j:4 948 ├── key: (1) 949 ├── fd: (1)-->(2-4), (3)~~>(1,2,4) 950 ├── scan b 951 │ ├── columns: k:1!null u:2 v:3 j:4 952 │ ├── key: (1) 953 │ └── fd: (1)-->(2-4), (3)~~>(1,2,4) 954 └── filters 955 └── j:4 @> '{"a": {}}' [outer=(4)] 956 957 opt 958 SELECT * FROM b WHERE j @> '{"a": []}' 959 ---- 960 select 961 ├── columns: k:1!null u:2 v:3 j:4 962 ├── key: (1) 963 ├── fd: (1)-->(2-4), (3)~~>(1,2,4) 964 ├── scan b 965 │ ├── columns: k:1!null u:2 v:3 j:4 966 │ ├── key: (1) 967 │ └── fd: (1)-->(2-4), (3)~~>(1,2,4) 968 └── filters 969 └── j:4 @> '{"a": []}' [outer=(4)] 970 971 # GenerateInvertedIndexScans propagates row-level locking information. 972 opt 973 SELECT k FROM b WHERE j @> '{"a": "b"}' FOR UPDATE 974 ---- 975 project 976 ├── columns: k:1!null 977 ├── volatile, side-effects 978 ├── key: (1) 979 └── index-join b 980 ├── columns: k:1!null j:4 981 ├── volatile, side-effects 982 ├── key: (1) 983 ├── fd: (1)-->(4) 984 └── scan b@inv_idx 985 ├── columns: k:1!null 986 ├── constraint: /4/1: [/'{"a": "b"}' - /'{"a": "b"}'] 987 ├── locking: for-update 988 ├── volatile, side-effects 989 └── key: (1) 990 991 # Tests for array inverted indexes. 992 opt 993 SELECT k FROM c WHERE a @> ARRAY[1] 994 ---- 995 project 996 ├── columns: k:1!null 997 ├── key: (1) 998 └── index-join c 999 ├── columns: k:1!null a:2 1000 ├── key: (1) 1001 ├── fd: (1)-->(2) 1002 └── scan c@inv_idx 1003 ├── columns: k:1!null 1004 ├── constraint: /2/1: [/ARRAY[1] - /ARRAY[1]] 1005 └── key: (1) 1006 1007 opt 1008 SELECT k FROM c WHERE a @> ARRAY[1,3,1,5] 1009 ---- 1010 project 1011 ├── columns: k:1!null 1012 ├── key: (1) 1013 └── inner-join (lookup c) 1014 ├── columns: k:1!null a:2 1015 ├── key columns: [1] = [1] 1016 ├── lookup columns are key 1017 ├── key: (1) 1018 ├── fd: (1)-->(2) 1019 ├── inner-join (zigzag c@inv_idx c@inv_idx) 1020 │ ├── columns: k:1!null 1021 │ ├── eq columns: [1] = [1] 1022 │ ├── left fixed columns: [2] = [ARRAY[1]] 1023 │ ├── right fixed columns: [2] = [ARRAY[3]] 1024 │ └── filters (true) 1025 └── filters 1026 └── a:2 @> ARRAY[1,3,1,5] [outer=(2)] 1027 1028 opt 1029 SELECT k FROM c WHERE a @> ARRAY[]::INT[] 1030 ---- 1031 project 1032 ├── columns: k:1!null 1033 ├── key: (1) 1034 └── select 1035 ├── columns: k:1!null a:2 1036 ├── key: (1) 1037 ├── fd: (1)-->(2) 1038 ├── scan c 1039 │ ├── columns: k:1!null a:2 1040 │ ├── key: (1) 1041 │ └── fd: (1)-->(2) 1042 └── filters 1043 └── a:2 @> ARRAY[] [outer=(2)] 1044 1045 opt 1046 SELECT k FROM c WHERE a IS NULL 1047 ---- 1048 project 1049 ├── columns: k:1!null 1050 ├── key: (1) 1051 └── select 1052 ├── columns: k:1!null a:2 1053 ├── key: (1) 1054 ├── fd: ()-->(2) 1055 ├── scan c 1056 │ ├── columns: k:1!null a:2 1057 │ ├── key: (1) 1058 │ └── fd: (1)-->(2) 1059 └── filters 1060 └── a:2 IS NULL [outer=(2), constraints=(/2: [/NULL - /NULL]; tight), fd=()-->(2)] 1061 1062 1063 # -------------------------------------------------- 1064 # SplitDisjunction 1065 # -------------------------------------------------- 1066 1067 # TODO(mgartner): PruneAggCols should be pruning columns from the DistinctOn 1068 # and further down the expression tree, ultimatly eliminating the index-joins. 1069 # PruneAggCols does not run in this case because normalization rules do not run 1070 # at the root tree generated by an exploration rule. 1071 opt expect=SplitDisjunction 1072 SELECT k FROM d WHERE u = 1 OR v = 1 1073 ---- 1074 project 1075 ├── columns: k:1!null 1076 ├── key: (1) 1077 └── distinct-on 1078 ├── columns: k:1!null u:2 v:3 1079 ├── grouping columns: k:1!null 1080 ├── key: (1) 1081 ├── fd: (1)-->(2,3) 1082 ├── union-all 1083 │ ├── columns: k:1!null u:2 v:3 1084 │ ├── left columns: k:1!null u:2 v:3 1085 │ ├── right columns: k:5 u:6 v:7 1086 │ ├── index-join d 1087 │ │ ├── columns: k:1!null u:2!null v:3 1088 │ │ ├── key: (1) 1089 │ │ ├── fd: ()-->(2), (1)-->(3) 1090 │ │ └── scan d@u 1091 │ │ ├── columns: k:1!null u:2!null 1092 │ │ ├── constraint: /2/1: [/1 - /1] 1093 │ │ ├── key: (1) 1094 │ │ └── fd: ()-->(2) 1095 │ └── index-join d 1096 │ ├── columns: k:5!null u:6 v:7!null 1097 │ ├── key: (5) 1098 │ ├── fd: ()-->(7), (5)-->(6) 1099 │ └── scan d@v 1100 │ ├── columns: k:5!null v:7!null 1101 │ ├── constraint: /7/5: [/1 - /1] 1102 │ ├── key: (5) 1103 │ └── fd: ()-->(7) 1104 └── aggregations 1105 ├── const-agg [as=u:2, outer=(2)] 1106 │ └── u:2 1107 └── const-agg [as=v:3, outer=(3)] 1108 └── v:3 1109 1110 opt expect=SplitDisjunction 1111 SELECT * FROM d WHERE w = 1 AND (u = 1 OR v = 1) 1112 ---- 1113 distinct-on 1114 ├── columns: k:1!null u:2 v:3 w:4!null 1115 ├── grouping columns: k:1!null 1116 ├── key: (1) 1117 ├── fd: ()-->(4), (1)-->(2,3) 1118 ├── union-all 1119 │ ├── columns: k:1!null u:2 v:3 w:4!null 1120 │ ├── left columns: k:1!null u:2 v:3 w:4!null 1121 │ ├── right columns: k:5 u:6 v:7 w:8 1122 │ ├── select 1123 │ │ ├── columns: k:1!null u:2!null v:3 w:4!null 1124 │ │ ├── key: (1) 1125 │ │ ├── fd: ()-->(2,4), (1)-->(3) 1126 │ │ ├── index-join d 1127 │ │ │ ├── columns: k:1!null u:2 v:3 w:4 1128 │ │ │ ├── key: (1) 1129 │ │ │ ├── fd: ()-->(2), (1)-->(3,4) 1130 │ │ │ └── scan d@u 1131 │ │ │ ├── columns: k:1!null u:2!null 1132 │ │ │ ├── constraint: /2/1: [/1 - /1] 1133 │ │ │ ├── key: (1) 1134 │ │ │ └── fd: ()-->(2) 1135 │ │ └── filters 1136 │ │ └── w:4 = 1 [outer=(4), constraints=(/4: [/1 - /1]; tight), fd=()-->(4)] 1137 │ └── select 1138 │ ├── columns: k:5!null u:6 v:7!null w:8!null 1139 │ ├── key: (5) 1140 │ ├── fd: ()-->(7,8), (5)-->(6) 1141 │ ├── index-join d 1142 │ │ ├── columns: k:5!null u:6 v:7 w:8 1143 │ │ ├── key: (5) 1144 │ │ ├── fd: ()-->(7), (5)-->(6,8) 1145 │ │ └── scan d@v 1146 │ │ ├── columns: k:5!null v:7!null 1147 │ │ ├── constraint: /7/5: [/1 - /1] 1148 │ │ ├── key: (5) 1149 │ │ └── fd: ()-->(7) 1150 │ └── filters 1151 │ └── w:8 = 1 [outer=(8), constraints=(/8: [/1 - /1]; tight), fd=()-->(8)] 1152 └── aggregations 1153 ├── const-agg [as=u:2, outer=(2)] 1154 │ └── u:2 1155 ├── const-agg [as=v:3, outer=(3)] 1156 │ └── v:3 1157 └── const-agg [as=w:4, outer=(4)] 1158 └── w:4 1159 1160 opt expect=SplitDisjunction 1161 SELECT k FROM d WHERE (u = 1 OR v = 2) AND (u = 10 OR v = 20) 1162 ---- 1163 project 1164 ├── columns: k:1!null 1165 ├── key: (1) 1166 └── distinct-on 1167 ├── columns: k:1!null u:2 v:3 1168 ├── grouping columns: k:1!null 1169 ├── key: (1) 1170 ├── fd: (1)-->(2,3) 1171 ├── union-all 1172 │ ├── columns: k:1!null u:2!null v:3!null 1173 │ ├── left columns: k:1!null u:2!null v:3!null 1174 │ ├── right columns: k:5 u:6 v:7 1175 │ ├── inner-join (zigzag d@u d@v) 1176 │ │ ├── columns: k:1!null u:2!null v:3!null 1177 │ │ ├── eq columns: [1] = [1] 1178 │ │ ├── left fixed columns: [2] = [1] 1179 │ │ ├── right fixed columns: [3] = [20] 1180 │ │ ├── key: (1) 1181 │ │ ├── fd: ()-->(2,3) 1182 │ │ └── filters 1183 │ │ ├── u:2 = 1 [outer=(2), constraints=(/2: [/1 - /1]; tight), fd=()-->(2)] 1184 │ │ └── v:3 = 20 [outer=(3), constraints=(/3: [/20 - /20]; tight), fd=()-->(3)] 1185 │ └── inner-join (zigzag d@u d@v) 1186 │ ├── columns: k:5!null u:6!null v:7!null 1187 │ ├── eq columns: [5] = [5] 1188 │ ├── left fixed columns: [6] = [10] 1189 │ ├── right fixed columns: [7] = [2] 1190 │ ├── key: (5) 1191 │ ├── fd: ()-->(6,7) 1192 │ └── filters 1193 │ ├── v:7 = 2 [outer=(7), constraints=(/7: [/2 - /2]; tight), fd=()-->(7)] 1194 │ └── u:6 = 10 [outer=(6), constraints=(/6: [/10 - /10]; tight), fd=()-->(6)] 1195 └── aggregations 1196 ├── const-agg [as=u:2, outer=(2)] 1197 │ └── u:2 1198 └── const-agg [as=v:3, outer=(3)] 1199 └── v:3 1200 1201 opt expect=SplitDisjunction 1202 SELECT sum(k) FROM d WHERE u = 1 OR v = 1 1203 ---- 1204 scalar-group-by 1205 ├── columns: sum:5 1206 ├── cardinality: [1 - 1] 1207 ├── key: () 1208 ├── fd: ()-->(5) 1209 ├── distinct-on 1210 │ ├── columns: k:1!null u:2 v:3 1211 │ ├── grouping columns: k:1!null 1212 │ ├── key: (1) 1213 │ ├── fd: (1)-->(2,3) 1214 │ ├── union-all 1215 │ │ ├── columns: k:1!null u:2 v:3 1216 │ │ ├── left columns: k:1!null u:2 v:3 1217 │ │ ├── right columns: k:6 u:7 v:8 1218 │ │ ├── index-join d 1219 │ │ │ ├── columns: k:1!null u:2!null v:3 1220 │ │ │ ├── key: (1) 1221 │ │ │ ├── fd: ()-->(2), (1)-->(3) 1222 │ │ │ └── scan d@u 1223 │ │ │ ├── columns: k:1!null u:2!null 1224 │ │ │ ├── constraint: /2/1: [/1 - /1] 1225 │ │ │ ├── key: (1) 1226 │ │ │ └── fd: ()-->(2) 1227 │ │ └── index-join d 1228 │ │ ├── columns: k:6!null u:7 v:8!null 1229 │ │ ├── key: (6) 1230 │ │ ├── fd: ()-->(8), (6)-->(7) 1231 │ │ └── scan d@v 1232 │ │ ├── columns: k:6!null v:8!null 1233 │ │ ├── constraint: /8/6: [/1 - /1] 1234 │ │ ├── key: (6) 1235 │ │ └── fd: ()-->(8) 1236 │ └── aggregations 1237 │ ├── const-agg [as=u:2, outer=(2)] 1238 │ │ └── u:2 1239 │ └── const-agg [as=v:3, outer=(3)] 1240 │ └── v:3 1241 └── aggregations 1242 └── sum [as=sum:5, outer=(1)] 1243 └── k:1 1244 1245 # Multi-column primary key. 1246 opt expect=SplitDisjunction 1247 SELECT k, j FROM f WHERE u = 1 OR v = 2 1248 ---- 1249 project 1250 ├── columns: k:1!null j:2!null 1251 ├── key: (1,2) 1252 └── distinct-on 1253 ├── columns: k:1!null j:2!null u:3 v:4 1254 ├── grouping columns: k:1!null j:2!null 1255 ├── key: (1,2) 1256 ├── fd: (1,2)-->(3,4) 1257 ├── union-all 1258 │ ├── columns: k:1!null j:2!null u:3 v:4 1259 │ ├── left columns: k:1!null j:2!null u:3 v:4 1260 │ ├── right columns: k:5 j:6 u:7 v:8 1261 │ ├── index-join f 1262 │ │ ├── columns: k:1!null j:2!null u:3!null v:4 1263 │ │ ├── key: (1,2) 1264 │ │ ├── fd: ()-->(3), (1,2)-->(4) 1265 │ │ └── scan f@u 1266 │ │ ├── columns: k:1!null j:2!null u:3!null 1267 │ │ ├── constraint: /3/1/2: [/1 - /1] 1268 │ │ ├── key: (1,2) 1269 │ │ └── fd: ()-->(3) 1270 │ └── index-join f 1271 │ ├── columns: k:5!null j:6!null u:7 v:8!null 1272 │ ├── key: (5,6) 1273 │ ├── fd: ()-->(8), (5,6)-->(7) 1274 │ └── scan f@v 1275 │ ├── columns: k:5!null j:6!null v:8!null 1276 │ ├── constraint: /8/5/6: [/2 - /2] 1277 │ ├── key: (5,6) 1278 │ └── fd: ()-->(8) 1279 └── aggregations 1280 ├── const-agg [as=u:3, outer=(3)] 1281 │ └── u:3 1282 └── const-agg [as=v:4, outer=(4)] 1283 └── v:4 1284 1285 # Don't expand INs to many ORs. 1286 opt expect=SplitDisjunction 1287 SELECT k FROM d WHERE u IN (1, 2, 3, 4) OR v IN (5, 6, 7, 8) 1288 ---- 1289 project 1290 ├── columns: k:1!null 1291 ├── key: (1) 1292 └── distinct-on 1293 ├── columns: k:1!null u:2 v:3 1294 ├── grouping columns: k:1!null 1295 ├── key: (1) 1296 ├── fd: (1)-->(2,3) 1297 ├── union-all 1298 │ ├── columns: k:1!null u:2 v:3 1299 │ ├── left columns: k:1!null u:2 v:3 1300 │ ├── right columns: k:5 u:6 v:7 1301 │ ├── index-join d 1302 │ │ ├── columns: k:1!null u:2!null v:3 1303 │ │ ├── key: (1) 1304 │ │ ├── fd: (1)-->(2,3) 1305 │ │ └── scan d@u 1306 │ │ ├── columns: k:1!null u:2!null 1307 │ │ ├── constraint: /2/1: [/1 - /4] 1308 │ │ ├── key: (1) 1309 │ │ └── fd: (1)-->(2) 1310 │ └── index-join d 1311 │ ├── columns: k:5!null u:6 v:7!null 1312 │ ├── key: (5) 1313 │ ├── fd: (5)-->(6,7) 1314 │ └── scan d@v 1315 │ ├── columns: k:5!null v:7!null 1316 │ ├── constraint: /7/5: [/5 - /8] 1317 │ ├── key: (5) 1318 │ └── fd: (5)-->(7) 1319 └── aggregations 1320 ├── const-agg [as=u:2, outer=(2)] 1321 │ └── u:2 1322 └── const-agg [as=v:3, outer=(3)] 1323 └── v:3 1324 1325 # Split and constrain with an inverted index on JSONB on one side. 1326 opt expect=SplitDisjunction 1327 SELECT k FROM b WHERE k = 1 OR j @> '{"foo": "bar"}' 1328 ---- 1329 project 1330 ├── columns: k:1!null 1331 ├── key: (1) 1332 └── distinct-on 1333 ├── columns: k:1!null j:4 1334 ├── grouping columns: k:1!null 1335 ├── key: (1) 1336 ├── fd: (1)-->(4) 1337 ├── union-all 1338 │ ├── columns: k:1!null j:4 1339 │ ├── left columns: k:1!null j:4 1340 │ ├── right columns: k:5 j:8 1341 │ ├── scan b 1342 │ │ ├── columns: k:1!null j:4 1343 │ │ ├── constraint: /1: [/1 - /1] 1344 │ │ ├── cardinality: [0 - 1] 1345 │ │ ├── key: () 1346 │ │ └── fd: ()-->(1,4) 1347 │ └── index-join b 1348 │ ├── columns: k:5!null j:8 1349 │ ├── key: (5) 1350 │ ├── fd: (5)-->(8) 1351 │ └── scan b@inv_idx 1352 │ ├── columns: k:5!null 1353 │ ├── constraint: /8/5: [/'{"foo": "bar"}' - /'{"foo": "bar"}'] 1354 │ └── key: (5) 1355 └── aggregations 1356 └── const-agg [as=j:4, outer=(4)] 1357 └── j:4 1358 1359 # Split and constrain with an inverted index on an array on one side. 1360 opt expect=SplitDisjunction 1361 SELECT k FROM c WHERE k = 1 OR a @> ARRAY[2] 1362 ---- 1363 project 1364 ├── columns: k:1!null 1365 ├── key: (1) 1366 └── distinct-on 1367 ├── columns: k:1!null a:2 1368 ├── grouping columns: k:1!null 1369 ├── key: (1) 1370 ├── fd: (1)-->(2) 1371 ├── union-all 1372 │ ├── columns: k:1!null a:2 1373 │ ├── left columns: k:1!null a:2 1374 │ ├── right columns: k:4 a:5 1375 │ ├── scan c 1376 │ │ ├── columns: k:1!null a:2 1377 │ │ ├── constraint: /1: [/1 - /1] 1378 │ │ ├── cardinality: [0 - 1] 1379 │ │ ├── key: () 1380 │ │ └── fd: ()-->(1,2) 1381 │ └── index-join c 1382 │ ├── columns: k:4!null a:5 1383 │ ├── key: (4) 1384 │ ├── fd: (4)-->(5) 1385 │ └── scan c@inv_idx 1386 │ ├── columns: k:4!null 1387 │ ├── constraint: /5/4: [/ARRAY[2] - /ARRAY[2]] 1388 │ └── key: (4) 1389 └── aggregations 1390 └── const-agg [as=a:2, outer=(2)] 1391 └── a:2 1392 1393 # Uncorrelated subquery. 1394 opt expect=SplitDisjunction 1395 SELECT k FROM d WHERE (u = 1 OR v = 1) AND EXISTS (SELECT u, v FROM a) 1396 ---- 1397 project 1398 ├── columns: k:1!null 1399 ├── key: (1) 1400 └── distinct-on 1401 ├── columns: d.k:1!null d.u:2 d.v:3 1402 ├── grouping columns: d.k:1!null 1403 ├── key: (1) 1404 ├── fd: (1)-->(2,3) 1405 ├── union-all 1406 │ ├── columns: d.k:1!null d.u:2 d.v:3 1407 │ ├── left columns: d.k:1!null d.u:2 d.v:3 1408 │ ├── right columns: d.k:8 d.u:9 d.v:10 1409 │ ├── index-join d 1410 │ │ ├── columns: d.k:1!null d.u:2!null d.v:3 1411 │ │ ├── key: (1) 1412 │ │ ├── fd: ()-->(2), (1)-->(3) 1413 │ │ └── select 1414 │ │ ├── columns: d.k:1!null d.u:2!null 1415 │ │ ├── key: (1) 1416 │ │ ├── fd: ()-->(2) 1417 │ │ ├── scan d@u 1418 │ │ │ ├── columns: d.k:1!null d.u:2!null 1419 │ │ │ ├── constraint: /2/1: [/1 - /1] 1420 │ │ │ ├── key: (1) 1421 │ │ │ └── fd: ()-->(2) 1422 │ │ └── filters 1423 │ │ └── exists [subquery] 1424 │ │ └── scan a 1425 │ │ ├── columns: a.u:6 a.v:7 1426 │ │ ├── limit: 1 1427 │ │ ├── key: () 1428 │ │ └── fd: ()-->(6,7) 1429 │ └── index-join d 1430 │ ├── columns: d.k:8!null d.u:9 d.v:10!null 1431 │ ├── key: (8) 1432 │ ├── fd: ()-->(10), (8)-->(9) 1433 │ └── select 1434 │ ├── columns: d.k:8!null d.v:10!null 1435 │ ├── key: (8) 1436 │ ├── fd: ()-->(10) 1437 │ ├── scan d@v 1438 │ │ ├── columns: d.k:8!null d.v:10!null 1439 │ │ ├── constraint: /10/8: [/1 - /1] 1440 │ │ ├── key: (8) 1441 │ │ └── fd: ()-->(10) 1442 │ └── filters 1443 │ └── exists [subquery] 1444 │ └── scan a 1445 │ ├── columns: a.u:6 a.v:7 1446 │ ├── limit: 1 1447 │ ├── key: () 1448 │ └── fd: ()-->(6,7) 1449 └── aggregations 1450 ├── const-agg [as=d.u:2, outer=(2)] 1451 │ └── d.u:2 1452 └── const-agg [as=d.v:3, outer=(3)] 1453 └── d.v:3 1454 1455 # Correlated subquery. 1456 opt expect=SplitDisjunction 1457 SELECT k FROM d WHERE (u = 1 OR v = 1) AND EXISTS (SELECT * FROM a WHERE a.u = d.u) 1458 ---- 1459 project 1460 ├── columns: k:1!null 1461 ├── key: (1) 1462 └── project 1463 ├── columns: d.k:1!null d.u:2 d.v:3 1464 ├── key: (1) 1465 ├── fd: (1)-->(2,3) 1466 └── inner-join (hash) 1467 ├── columns: d.k:1!null d.u:2!null d.v:3 a.u:6!null 1468 ├── key: (1) 1469 ├── fd: (1)-->(2,3), (2)==(6), (6)==(2) 1470 ├── distinct-on 1471 │ ├── columns: d.k:1!null d.u:2 d.v:3 1472 │ ├── grouping columns: d.k:1!null 1473 │ ├── key: (1) 1474 │ ├── fd: (1)-->(2,3) 1475 │ ├── union-all 1476 │ │ ├── columns: d.k:1!null d.u:2 d.v:3 1477 │ │ ├── left columns: d.k:1!null d.u:2 d.v:3 1478 │ │ ├── right columns: d.k:8 d.u:9 d.v:10 1479 │ │ ├── index-join d 1480 │ │ │ ├── columns: d.k:1!null d.u:2!null d.v:3 1481 │ │ │ ├── key: (1) 1482 │ │ │ ├── fd: ()-->(2), (1)-->(3) 1483 │ │ │ └── scan d@u 1484 │ │ │ ├── columns: d.k:1!null d.u:2!null 1485 │ │ │ ├── constraint: /2/1: [/1 - /1] 1486 │ │ │ ├── key: (1) 1487 │ │ │ └── fd: ()-->(2) 1488 │ │ └── index-join d 1489 │ │ ├── columns: d.k:8!null d.u:9 d.v:10!null 1490 │ │ ├── key: (8) 1491 │ │ ├── fd: ()-->(10), (8)-->(9) 1492 │ │ └── scan d@v 1493 │ │ ├── columns: d.k:8!null d.v:10!null 1494 │ │ ├── constraint: /10/8: [/1 - /1] 1495 │ │ ├── key: (8) 1496 │ │ └── fd: ()-->(10) 1497 │ └── aggregations 1498 │ ├── const-agg [as=d.u:2, outer=(2)] 1499 │ │ └── d.u:2 1500 │ └── const-agg [as=d.v:3, outer=(3)] 1501 │ └── d.v:3 1502 ├── distinct-on 1503 │ ├── columns: a.u:6 1504 │ ├── grouping columns: a.u:6 1505 │ ├── internal-ordering: +6 1506 │ ├── key: (6) 1507 │ └── scan a@u 1508 │ ├── columns: a.u:6 1509 │ └── ordering: +6 1510 └── filters 1511 └── a.u:6 = d.u:2 [outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)] 1512 1513 # Correlated subquery with references to outer columns not in the scan columns. 1514 opt expect=SplitDisjunction 1515 SELECT k FROM d WHERE (u = 1 OR v = 1) AND EXISTS (SELECT * FROM a WHERE a.u = d.w) 1516 ---- 1517 project 1518 ├── columns: k:1!null 1519 ├── key: (1) 1520 └── project 1521 ├── columns: d.k:1!null d.u:2 d.v:3 w:4 1522 ├── key: (1) 1523 ├── fd: (1)-->(2-4) 1524 └── inner-join (hash) 1525 ├── columns: d.k:1!null d.u:2 d.v:3 w:4!null a.u:6!null 1526 ├── key: (1) 1527 ├── fd: (1)-->(2-4), (4)==(6), (6)==(4) 1528 ├── distinct-on 1529 │ ├── columns: d.k:1!null d.u:2 d.v:3 w:4 1530 │ ├── grouping columns: d.k:1!null 1531 │ ├── key: (1) 1532 │ ├── fd: (1)-->(2-4) 1533 │ ├── union-all 1534 │ │ ├── columns: d.k:1!null d.u:2 d.v:3 w:4 1535 │ │ ├── left columns: d.k:1!null d.u:2 d.v:3 w:4 1536 │ │ ├── right columns: d.k:8 d.u:9 d.v:10 w:11 1537 │ │ ├── index-join d 1538 │ │ │ ├── columns: d.k:1!null d.u:2!null d.v:3 w:4 1539 │ │ │ ├── key: (1) 1540 │ │ │ ├── fd: ()-->(2), (1)-->(3,4) 1541 │ │ │ └── scan d@u 1542 │ │ │ ├── columns: d.k:1!null d.u:2!null 1543 │ │ │ ├── constraint: /2/1: [/1 - /1] 1544 │ │ │ ├── key: (1) 1545 │ │ │ └── fd: ()-->(2) 1546 │ │ └── index-join d 1547 │ │ ├── columns: d.k:8!null d.u:9 d.v:10!null w:11 1548 │ │ ├── key: (8) 1549 │ │ ├── fd: ()-->(10), (8)-->(9,11) 1550 │ │ └── scan d@v 1551 │ │ ├── columns: d.k:8!null d.v:10!null 1552 │ │ ├── constraint: /10/8: [/1 - /1] 1553 │ │ ├── key: (8) 1554 │ │ └── fd: ()-->(10) 1555 │ └── aggregations 1556 │ ├── const-agg [as=d.u:2, outer=(2)] 1557 │ │ └── d.u:2 1558 │ ├── const-agg [as=d.v:3, outer=(3)] 1559 │ │ └── d.v:3 1560 │ └── const-agg [as=w:4, outer=(4)] 1561 │ └── w:4 1562 ├── distinct-on 1563 │ ├── columns: a.u:6 1564 │ ├── grouping columns: a.u:6 1565 │ ├── internal-ordering: +6 1566 │ ├── key: (6) 1567 │ └── scan a@u 1568 │ ├── columns: a.u:6 1569 │ └── ordering: +6 1570 └── filters 1571 └── a.u:6 = w:4 [outer=(4,6), constraints=(/4: (/NULL - ]; /6: (/NULL - ]), fd=(4)==(6), (6)==(4)] 1572 1573 # Apply when outer columns of both sides of OR are a subset of index columns. 1574 opt expect=SplitDisjunction 1575 SELECT k, u, v FROM e WHERE u = 1 OR v = 1 1576 ---- 1577 distinct-on 1578 ├── columns: k:1!null u:2 v:3 1579 ├── grouping columns: k:1!null 1580 ├── key: (1) 1581 ├── fd: (1)-->(2,3) 1582 ├── union-all 1583 │ ├── columns: k:1!null u:2 v:3 1584 │ ├── left columns: k:1!null u:2 v:3 1585 │ ├── right columns: k:5 u:6 v:7 1586 │ ├── index-join e 1587 │ │ ├── columns: k:1!null u:2!null v:3 1588 │ │ ├── key: (1) 1589 │ │ ├── fd: ()-->(2), (1)-->(3) 1590 │ │ └── scan e@uw 1591 │ │ ├── columns: k:1!null u:2!null 1592 │ │ ├── constraint: /2/4/1: [/1 - /1] 1593 │ │ ├── key: (1) 1594 │ │ └── fd: ()-->(2) 1595 │ └── index-join e 1596 │ ├── columns: k:5!null u:6 v:7!null 1597 │ ├── key: (5) 1598 │ ├── fd: ()-->(7), (5)-->(6) 1599 │ └── scan e@vw 1600 │ ├── columns: k:5!null v:7!null 1601 │ ├── constraint: /7/8/5: [/1 - /1] 1602 │ ├── key: (5) 1603 │ └── fd: ()-->(7) 1604 └── aggregations 1605 ├── const-agg [as=u:2, outer=(2)] 1606 │ └── u:2 1607 └── const-agg [as=v:3, outer=(3)] 1608 └── v:3 1609 1610 # Apply when outer columns of both sides of OR are a superset of index columns. 1611 opt expect=SplitDisjunction 1612 SELECT k, u, v FROM d WHERE (u = 1 AND w = 2) OR (v = 1 AND w = 3) 1613 ---- 1614 project 1615 ├── columns: k:1!null u:2 v:3 1616 ├── key: (1) 1617 ├── fd: (1)-->(2,3) 1618 └── distinct-on 1619 ├── columns: k:1!null u:2 v:3 w:4!null 1620 ├── grouping columns: k:1!null 1621 ├── key: (1) 1622 ├── fd: (1)-->(2-4) 1623 ├── union-all 1624 │ ├── columns: k:1!null u:2 v:3 w:4!null 1625 │ ├── left columns: k:1!null u:2 v:3 w:4!null 1626 │ ├── right columns: k:5 u:6 v:7 w:8 1627 │ ├── select 1628 │ │ ├── columns: k:1!null u:2!null v:3 w:4!null 1629 │ │ ├── key: (1) 1630 │ │ ├── fd: ()-->(2,4), (1)-->(3) 1631 │ │ ├── index-join d 1632 │ │ │ ├── columns: k:1!null u:2 v:3 w:4 1633 │ │ │ ├── key: (1) 1634 │ │ │ ├── fd: ()-->(2), (1)-->(3,4) 1635 │ │ │ └── scan d@u 1636 │ │ │ ├── columns: k:1!null u:2!null 1637 │ │ │ ├── constraint: /2/1: [/1 - /1] 1638 │ │ │ ├── key: (1) 1639 │ │ │ └── fd: ()-->(2) 1640 │ │ └── filters 1641 │ │ └── w:4 = 2 [outer=(4), constraints=(/4: [/2 - /2]; tight), fd=()-->(4)] 1642 │ └── select 1643 │ ├── columns: k:5!null u:6 v:7!null w:8!null 1644 │ ├── key: (5) 1645 │ ├── fd: ()-->(7,8), (5)-->(6) 1646 │ ├── index-join d 1647 │ │ ├── columns: k:5!null u:6 v:7 w:8 1648 │ │ ├── key: (5) 1649 │ │ ├── fd: ()-->(7), (5)-->(6,8) 1650 │ │ └── scan d@v 1651 │ │ ├── columns: k:5!null v:7!null 1652 │ │ ├── constraint: /7/5: [/1 - /1] 1653 │ │ ├── key: (5) 1654 │ │ └── fd: ()-->(7) 1655 │ └── filters 1656 │ └── w:8 = 3 [outer=(8), constraints=(/8: [/3 - /3]; tight), fd=()-->(8)] 1657 └── aggregations 1658 ├── const-agg [as=u:2, outer=(2)] 1659 │ └── u:2 1660 ├── const-agg [as=v:3, outer=(3)] 1661 │ └── v:3 1662 └── const-agg [as=w:4, outer=(4)] 1663 └── w:4 1664 1665 # Group sub-expr with the same columns together. 1666 opt expect=SplitDisjunction 1667 SELECT k, u, v FROM d WHERE (u = 1 OR v = 2) OR (u = 3 OR v = 4) 1668 ---- 1669 distinct-on 1670 ├── columns: k:1!null u:2 v:3 1671 ├── grouping columns: k:1!null 1672 ├── key: (1) 1673 ├── fd: (1)-->(2,3) 1674 ├── union-all 1675 │ ├── columns: k:1!null u:2 v:3 1676 │ ├── left columns: k:1!null u:2 v:3 1677 │ ├── right columns: k:5 u:6 v:7 1678 │ ├── index-join d 1679 │ │ ├── columns: k:1!null u:2!null v:3 1680 │ │ ├── key: (1) 1681 │ │ ├── fd: (1)-->(2,3) 1682 │ │ └── scan d@u 1683 │ │ ├── columns: k:1!null u:2!null 1684 │ │ ├── constraint: /2/1 1685 │ │ │ ├── [/1 - /1] 1686 │ │ │ └── [/3 - /3] 1687 │ │ ├── key: (1) 1688 │ │ └── fd: (1)-->(2) 1689 │ └── index-join d 1690 │ ├── columns: k:5!null u:6 v:7!null 1691 │ ├── key: (5) 1692 │ ├── fd: (5)-->(6,7) 1693 │ └── scan d@v 1694 │ ├── columns: k:5!null v:7!null 1695 │ ├── constraint: /7/5 1696 │ │ ├── [/2 - /2] 1697 │ │ └── [/4 - /4] 1698 │ ├── key: (5) 1699 │ └── fd: (5)-->(7) 1700 └── aggregations 1701 ├── const-agg [as=u:2, outer=(2)] 1702 │ └── u:2 1703 └── const-agg [as=v:3, outer=(3)] 1704 └── v:3 1705 1706 # Group sub-expr with the same columns together. Output should have a single union expr. 1707 opt expect=SplitDisjunction 1708 SELECT k, u, v FROM d WHERE u = 1 OR u = 3 OR v = 2 OR v = 4 OR u = 5 OR v = 6 1709 ---- 1710 distinct-on 1711 ├── columns: k:1!null u:2 v:3 1712 ├── grouping columns: k:1!null 1713 ├── key: (1) 1714 ├── fd: (1)-->(2,3) 1715 ├── union-all 1716 │ ├── columns: k:1!null u:2 v:3 1717 │ ├── left columns: k:1!null u:2 v:3 1718 │ ├── right columns: k:5 u:6 v:7 1719 │ ├── index-join d 1720 │ │ ├── columns: k:1!null u:2!null v:3 1721 │ │ ├── key: (1) 1722 │ │ ├── fd: (1)-->(2,3) 1723 │ │ └── scan d@u 1724 │ │ ├── columns: k:1!null u:2!null 1725 │ │ ├── constraint: /2/1 1726 │ │ │ ├── [/1 - /1] 1727 │ │ │ ├── [/3 - /3] 1728 │ │ │ └── [/5 - /5] 1729 │ │ ├── key: (1) 1730 │ │ └── fd: (1)-->(2) 1731 │ └── index-join d 1732 │ ├── columns: k:5!null u:6 v:7!null 1733 │ ├── key: (5) 1734 │ ├── fd: (5)-->(6,7) 1735 │ └── scan d@v 1736 │ ├── columns: k:5!null v:7!null 1737 │ ├── constraint: /7/5 1738 │ │ ├── [/2 - /2] 1739 │ │ ├── [/4 - /4] 1740 │ │ └── [/6 - /6] 1741 │ ├── key: (5) 1742 │ └── fd: (5)-->(7) 1743 └── aggregations 1744 ├── const-agg [as=u:2, outer=(2)] 1745 │ └── u:2 1746 └── const-agg [as=v:3, outer=(3)] 1747 └── v:3 1748 1749 # Group sub-expr with the same columns together. Output should have a single union expr. 1750 opt expect=SplitDisjunction 1751 SELECT k, u, v FROM d WHERE (u = 3 OR v = 2) OR (u = 5 OR v = 4) OR v = 6 1752 ---- 1753 distinct-on 1754 ├── columns: k:1!null u:2 v:3 1755 ├── grouping columns: k:1!null 1756 ├── key: (1) 1757 ├── fd: (1)-->(2,3) 1758 ├── union-all 1759 │ ├── columns: k:1!null u:2 v:3 1760 │ ├── left columns: k:1!null u:2 v:3 1761 │ ├── right columns: k:5 u:6 v:7 1762 │ ├── index-join d 1763 │ │ ├── columns: k:1!null u:2!null v:3 1764 │ │ ├── key: (1) 1765 │ │ ├── fd: (1)-->(2,3) 1766 │ │ └── scan d@u 1767 │ │ ├── columns: k:1!null u:2!null 1768 │ │ ├── constraint: /2/1 1769 │ │ │ ├── [/3 - /3] 1770 │ │ │ └── [/5 - /5] 1771 │ │ ├── key: (1) 1772 │ │ └── fd: (1)-->(2) 1773 │ └── index-join d 1774 │ ├── columns: k:5!null u:6 v:7!null 1775 │ ├── key: (5) 1776 │ ├── fd: (5)-->(6,7) 1777 │ └── scan d@v 1778 │ ├── columns: k:5!null v:7!null 1779 │ ├── constraint: /7/5 1780 │ │ ├── [/2 - /2] 1781 │ │ ├── [/4 - /4] 1782 │ │ └── [/6 - /6] 1783 │ ├── key: (5) 1784 │ └── fd: (5)-->(7) 1785 └── aggregations 1786 ├── const-agg [as=u:2, outer=(2)] 1787 │ └── u:2 1788 └── const-agg [as=v:3, outer=(3)] 1789 └── v:3 1790 1791 # Find the first disjunction in the filters that have different column sets on 1792 # the left and right. 1793 opt expect=SplitDisjunction 1794 SELECT k FROM d WHERE (w = 1 OR w = 2) AND (u = 3 OR v = 4) 1795 ---- 1796 project 1797 ├── columns: k:1!null 1798 ├── key: (1) 1799 └── distinct-on 1800 ├── columns: k:1!null u:2 v:3 w:4!null 1801 ├── grouping columns: k:1!null 1802 ├── key: (1) 1803 ├── fd: (1)-->(2-4) 1804 ├── union-all 1805 │ ├── columns: k:1!null u:2 v:3 w:4!null 1806 │ ├── left columns: k:1!null u:2 v:3 w:4!null 1807 │ ├── right columns: k:5 u:6 v:7 w:8 1808 │ ├── select 1809 │ │ ├── columns: k:1!null u:2!null v:3 w:4!null 1810 │ │ ├── key: (1) 1811 │ │ ├── fd: ()-->(2), (1)-->(3,4) 1812 │ │ ├── index-join d 1813 │ │ │ ├── columns: k:1!null u:2 v:3 w:4 1814 │ │ │ ├── key: (1) 1815 │ │ │ ├── fd: ()-->(2), (1)-->(3,4) 1816 │ │ │ └── scan d@u 1817 │ │ │ ├── columns: k:1!null u:2!null 1818 │ │ │ ├── constraint: /2/1: [/3 - /3] 1819 │ │ │ ├── key: (1) 1820 │ │ │ └── fd: ()-->(2) 1821 │ │ └── filters 1822 │ │ └── (w:4 = 1) OR (w:4 = 2) [outer=(4), constraints=(/4: [/1 - /1] [/2 - /2]; tight)] 1823 │ └── select 1824 │ ├── columns: k:5!null u:6 v:7!null w:8!null 1825 │ ├── key: (5) 1826 │ ├── fd: ()-->(7), (5)-->(6,8) 1827 │ ├── index-join d 1828 │ │ ├── columns: k:5!null u:6 v:7 w:8 1829 │ │ ├── key: (5) 1830 │ │ ├── fd: ()-->(7), (5)-->(6,8) 1831 │ │ └── scan d@v 1832 │ │ ├── columns: k:5!null v:7!null 1833 │ │ ├── constraint: /7/5: [/4 - /4] 1834 │ │ ├── key: (5) 1835 │ │ └── fd: ()-->(7) 1836 │ └── filters 1837 │ └── (w:8 = 1) OR (w:8 = 2) [outer=(8), constraints=(/8: [/1 - /1] [/2 - /2]; tight)] 1838 └── aggregations 1839 ├── const-agg [as=u:2, outer=(2)] 1840 │ └── u:2 1841 ├── const-agg [as=v:3, outer=(3)] 1842 │ └── v:3 1843 └── const-agg [as=w:4, outer=(4)] 1844 └── w:4 1845 1846 # Find the first disjunction in the filters that have columns on the left and 1847 # right that constrain a scan. 1848 opt expect=SplitDisjunction 1849 SELECT k FROM d WHERE (u = 1 OR w = 2) AND (u = 3 OR v = 4) 1850 ---- 1851 project 1852 ├── columns: k:1!null 1853 ├── key: (1) 1854 └── distinct-on 1855 ├── columns: k:1!null u:2 v:3 w:4 1856 ├── grouping columns: k:1!null 1857 ├── key: (1) 1858 ├── fd: (1)-->(2-4) 1859 ├── union-all 1860 │ ├── columns: k:1!null u:2 v:3 w:4 1861 │ ├── left columns: k:1!null u:2 v:3 w:4 1862 │ ├── right columns: k:5 u:6 v:7 w:8 1863 │ ├── select 1864 │ │ ├── columns: k:1!null u:2!null v:3 w:4!null 1865 │ │ ├── key: (1) 1866 │ │ ├── fd: ()-->(2,4), (1)-->(3) 1867 │ │ ├── index-join d 1868 │ │ │ ├── columns: k:1!null u:2 v:3 w:4 1869 │ │ │ ├── key: (1) 1870 │ │ │ ├── fd: ()-->(2), (1)-->(3,4) 1871 │ │ │ └── scan d@u 1872 │ │ │ ├── columns: k:1!null u:2!null 1873 │ │ │ ├── constraint: /2/1: [/3 - /3] 1874 │ │ │ ├── key: (1) 1875 │ │ │ └── fd: ()-->(2) 1876 │ │ └── filters 1877 │ │ └── w:4 = 2 [outer=(4), constraints=(/4: [/2 - /2]; tight), fd=()-->(4)] 1878 │ └── select 1879 │ ├── columns: k:5!null u:6 v:7!null w:8 1880 │ ├── key: (5) 1881 │ ├── fd: ()-->(7), (5)-->(6,8) 1882 │ ├── index-join d 1883 │ │ ├── columns: k:5!null u:6 v:7 w:8 1884 │ │ ├── key: (5) 1885 │ │ ├── fd: ()-->(7), (5)-->(6,8) 1886 │ │ └── scan d@v 1887 │ │ ├── columns: k:5!null v:7!null 1888 │ │ ├── constraint: /7/5: [/4 - /4] 1889 │ │ ├── key: (5) 1890 │ │ └── fd: ()-->(7) 1891 │ └── filters 1892 │ └── (u:6 = 1) OR (w:8 = 2) [outer=(6,8)] 1893 └── aggregations 1894 ├── const-agg [as=u:2, outer=(2)] 1895 │ └── u:2 1896 ├── const-agg [as=v:3, outer=(3)] 1897 │ └── v:3 1898 └── const-agg [as=w:4, outer=(4)] 1899 └── w:4 1900 1901 # Don't apply when outer columns of both sides of OR do not intersect with index columns. 1902 opt expect-not=SplitDisjunction 1903 SELECT k, u, w FROM d WHERE u = 1 OR w = 1 1904 ---- 1905 select 1906 ├── columns: k:1!null u:2 w:4 1907 ├── key: (1) 1908 ├── fd: (1)-->(2,4) 1909 ├── scan d 1910 │ ├── columns: k:1!null u:2 w:4 1911 │ ├── key: (1) 1912 │ └── fd: (1)-->(2,4) 1913 └── filters 1914 └── (u:2 = 1) OR (w:4 = 1) [outer=(2,4)] 1915 1916 # Don't apply to queries without strict keys. 1917 opt expect-not=SplitDisjunction 1918 SELECT u, v FROM d WHERE u = 1 OR v = 1 1919 ---- 1920 project 1921 ├── columns: u:2 v:3 1922 └── distinct-on 1923 ├── columns: k:1!null u:2 v:3 1924 ├── grouping columns: k:1!null 1925 ├── key: (1) 1926 ├── fd: (1)-->(2,3) 1927 ├── union-all 1928 │ ├── columns: k:1!null u:2 v:3 1929 │ ├── left columns: k:1!null u:2 v:3 1930 │ ├── right columns: k:5 u:6 v:7 1931 │ ├── index-join d 1932 │ │ ├── columns: k:1!null u:2!null v:3 1933 │ │ ├── key: (1) 1934 │ │ ├── fd: ()-->(2), (1)-->(3) 1935 │ │ └── scan d@u 1936 │ │ ├── columns: k:1!null u:2!null 1937 │ │ ├── constraint: /2/1: [/1 - /1] 1938 │ │ ├── key: (1) 1939 │ │ └── fd: ()-->(2) 1940 │ └── index-join d 1941 │ ├── columns: k:5!null u:6 v:7!null 1942 │ ├── key: (5) 1943 │ ├── fd: ()-->(7), (5)-->(6) 1944 │ └── scan d@v 1945 │ ├── columns: k:5!null v:7!null 1946 │ ├── constraint: /7/5: [/1 - /1] 1947 │ ├── key: (5) 1948 │ └── fd: ()-->(7) 1949 └── aggregations 1950 ├── const-agg [as=u:2, outer=(2)] 1951 │ └── u:2 1952 └── const-agg [as=v:3, outer=(3)] 1953 └── v:3 1954 1955 # Don't apply to disjunctions with identical colsets on the left and right. 1956 opt expect-not=SplitDisjunction 1957 SELECT k FROM d WHERE u = 1 OR u = 5 1958 ---- 1959 project 1960 ├── columns: k:1!null 1961 ├── key: (1) 1962 └── scan d@u 1963 ├── columns: k:1!null u:2!null 1964 ├── constraint: /2/1 1965 │ ├── [/1 - /1] 1966 │ └── [/5 - /5] 1967 ├── key: (1) 1968 └── fd: (1)-->(2) 1969 1970 # Verifies that flags are copied to the duplicated scan. 1971 opt expect=SplitDisjunction 1972 SELECT k FROM a@{NO_INDEX_JOIN} WHERE u = 1 OR v = 1 1973 ---- 1974 project 1975 ├── columns: k:1!null 1976 ├── key: (1) 1977 └── distinct-on 1978 ├── columns: k:1!null u:2 v:3 1979 ├── grouping columns: k:1!null 1980 ├── key: (1) 1981 ├── fd: (1)-->(2,3), (3)~~>(1,2) 1982 ├── union-all 1983 │ ├── columns: k:1!null u:2 v:3 1984 │ ├── left columns: k:1!null u:2 v:3 1985 │ ├── right columns: k:4 u:5 v:6 1986 │ ├── scan a@u 1987 │ │ ├── columns: k:1!null u:2!null v:3 1988 │ │ ├── constraint: /2/1: [/1 - /1] 1989 │ │ ├── flags: no-index-join 1990 │ │ ├── key: (1) 1991 │ │ └── fd: ()-->(2), (1)-->(3), (3)~~>(1) 1992 │ └── scan a@v 1993 │ ├── columns: k:4!null u:5 v:6!null 1994 │ ├── constraint: /6: [/1 - /1] 1995 │ ├── flags: no-index-join 1996 │ ├── cardinality: [0 - 1] 1997 │ ├── key: () 1998 │ └── fd: ()-->(4-6) 1999 └── aggregations 2000 ├── const-agg [as=u:2, outer=(2)] 2001 │ └── u:2 2002 └── const-agg [as=v:3, outer=(3)] 2003 └── v:3 2004 2005 # Columns are passed-through correctly when EliminateUnionAllLeft is applied. 2006 opt expect=SplitDisjunction 2007 SELECT k FROM d WHERE u = 2 OR (v = 1 AND v = 3) 2008 ---- 2009 project 2010 ├── columns: k:1!null 2011 ├── key: (1) 2012 └── distinct-on 2013 ├── columns: k:1!null u:2!null v:3 2014 ├── grouping columns: k:1!null 2015 ├── internal-ordering: +1 opt(2) 2016 ├── key: (1) 2017 ├── fd: ()-->(2), (1)-->(3) 2018 ├── index-join d 2019 │ ├── columns: k:1!null u:2!null v:3 2020 │ ├── key: (1) 2021 │ ├── fd: ()-->(2), (1)-->(3) 2022 │ ├── ordering: +1 opt(2) [actual: +1] 2023 │ └── scan d@u 2024 │ ├── columns: k:1!null u:2!null 2025 │ ├── constraint: /2/1: [/2 - /2] 2026 │ ├── key: (1) 2027 │ ├── fd: ()-->(2) 2028 │ └── ordering: +1 opt(2) [actual: +1] 2029 └── aggregations 2030 ├── const-agg [as=u:2, outer=(2)] 2031 │ └── u:2 2032 └── const-agg [as=v:3, outer=(3)] 2033 └── v:3 2034 2035 # -------------------------------------------------- 2036 # SplitDisjunctionAddKey 2037 # -------------------------------------------------- 2038 2039 opt expect=SplitDisjunctionAddKey 2040 SELECT u, v FROM d WHERE u = 1 OR v = 1 2041 ---- 2042 project 2043 ├── columns: u:2 v:3 2044 └── distinct-on 2045 ├── columns: k:1!null u:2 v:3 2046 ├── grouping columns: k:1!null 2047 ├── key: (1) 2048 ├── fd: (1)-->(2,3) 2049 ├── union-all 2050 │ ├── columns: k:1!null u:2 v:3 2051 │ ├── left columns: k:1!null u:2 v:3 2052 │ ├── right columns: k:5 u:6 v:7 2053 │ ├── index-join d 2054 │ │ ├── columns: k:1!null u:2!null v:3 2055 │ │ ├── key: (1) 2056 │ │ ├── fd: ()-->(2), (1)-->(3) 2057 │ │ └── scan d@u 2058 │ │ ├── columns: k:1!null u:2!null 2059 │ │ ├── constraint: /2/1: [/1 - /1] 2060 │ │ ├── key: (1) 2061 │ │ └── fd: ()-->(2) 2062 │ └── index-join d 2063 │ ├── columns: k:5!null u:6 v:7!null 2064 │ ├── key: (5) 2065 │ ├── fd: ()-->(7), (5)-->(6) 2066 │ └── scan d@v 2067 │ ├── columns: k:5!null v:7!null 2068 │ ├── constraint: /7/5: [/1 - /1] 2069 │ ├── key: (5) 2070 │ └── fd: ()-->(7) 2071 └── aggregations 2072 ├── const-agg [as=u:2, outer=(2)] 2073 │ └── u:2 2074 └── const-agg [as=v:3, outer=(3)] 2075 └── v:3 2076 2077 opt expect=SplitDisjunctionAddKey 2078 SELECT u, v, w FROM d WHERE w = 1 AND (u = 1 OR v = 1) 2079 ---- 2080 project 2081 ├── columns: u:2 v:3 w:4!null 2082 ├── fd: ()-->(4) 2083 └── distinct-on 2084 ├── columns: k:1!null u:2 v:3 w:4!null 2085 ├── grouping columns: k:1!null 2086 ├── key: (1) 2087 ├── fd: (1)-->(2-4) 2088 ├── union-all 2089 │ ├── columns: k:1!null u:2 v:3 w:4!null 2090 │ ├── left columns: k:1!null u:2 v:3 w:4!null 2091 │ ├── right columns: k:5 u:6 v:7 w:8 2092 │ ├── select 2093 │ │ ├── columns: k:1!null u:2!null v:3 w:4!null 2094 │ │ ├── key: (1) 2095 │ │ ├── fd: ()-->(2,4), (1)-->(3) 2096 │ │ ├── index-join d 2097 │ │ │ ├── columns: k:1!null u:2 v:3 w:4 2098 │ │ │ ├── key: (1) 2099 │ │ │ ├── fd: ()-->(2), (1)-->(3,4) 2100 │ │ │ └── scan d@u 2101 │ │ │ ├── columns: k:1!null u:2!null 2102 │ │ │ ├── constraint: /2/1: [/1 - /1] 2103 │ │ │ ├── key: (1) 2104 │ │ │ └── fd: ()-->(2) 2105 │ │ └── filters 2106 │ │ └── w:4 = 1 [outer=(4), constraints=(/4: [/1 - /1]; tight), fd=()-->(4)] 2107 │ └── select 2108 │ ├── columns: k:5!null u:6 v:7!null w:8!null 2109 │ ├── key: (5) 2110 │ ├── fd: ()-->(7,8), (5)-->(6) 2111 │ ├── index-join d 2112 │ │ ├── columns: k:5!null u:6 v:7 w:8 2113 │ │ ├── key: (5) 2114 │ │ ├── fd: ()-->(7), (5)-->(6,8) 2115 │ │ └── scan d@v 2116 │ │ ├── columns: k:5!null v:7!null 2117 │ │ ├── constraint: /7/5: [/1 - /1] 2118 │ │ ├── key: (5) 2119 │ │ └── fd: ()-->(7) 2120 │ └── filters 2121 │ └── w:8 = 1 [outer=(8), constraints=(/8: [/1 - /1]; tight), fd=()-->(8)] 2122 └── aggregations 2123 ├── const-agg [as=u:2, outer=(2)] 2124 │ └── u:2 2125 ├── const-agg [as=v:3, outer=(3)] 2126 │ └── v:3 2127 └── const-agg [as=w:4, outer=(4)] 2128 └── w:4 2129 2130 opt expect=SplitDisjunctionAddKey 2131 SELECT u, v FROM d WHERE (u = 1 OR v = 2) AND (u = 10 OR v = 20) 2132 ---- 2133 project 2134 ├── columns: u:2 v:3 2135 └── distinct-on 2136 ├── columns: k:1!null u:2!null v:3!null 2137 ├── grouping columns: k:1!null 2138 ├── key: (1) 2139 ├── fd: (1)-->(2,3) 2140 ├── union-all 2141 │ ├── columns: k:1!null u:2!null v:3!null 2142 │ ├── left columns: k:1!null u:2!null v:3!null 2143 │ ├── right columns: k:5 u:6 v:7 2144 │ ├── inner-join (zigzag d@u d@v) 2145 │ │ ├── columns: k:1!null u:2!null v:3!null 2146 │ │ ├── eq columns: [1] = [1] 2147 │ │ ├── left fixed columns: [2] = [1] 2148 │ │ ├── right fixed columns: [3] = [20] 2149 │ │ ├── key: (1) 2150 │ │ ├── fd: ()-->(2,3) 2151 │ │ └── filters 2152 │ │ ├── u:2 = 1 [outer=(2), constraints=(/2: [/1 - /1]; tight), fd=()-->(2)] 2153 │ │ └── v:3 = 20 [outer=(3), constraints=(/3: [/20 - /20]; tight), fd=()-->(3)] 2154 │ └── inner-join (zigzag d@u d@v) 2155 │ ├── columns: k:5!null u:6!null v:7!null 2156 │ ├── eq columns: [5] = [5] 2157 │ ├── left fixed columns: [6] = [10] 2158 │ ├── right fixed columns: [7] = [2] 2159 │ ├── key: (5) 2160 │ ├── fd: ()-->(6,7) 2161 │ └── filters 2162 │ ├── v:7 = 2 [outer=(7), constraints=(/7: [/2 - /2]; tight), fd=()-->(7)] 2163 │ └── u:6 = 10 [outer=(6), constraints=(/6: [/10 - /10]; tight), fd=()-->(6)] 2164 └── aggregations 2165 ├── const-agg [as=u:2, outer=(2)] 2166 │ └── u:2 2167 └── const-agg [as=v:3, outer=(3)] 2168 └── v:3 2169 2170 opt expect=SplitDisjunctionAddKey 2171 SELECT count(*) FROM d WHERE u = 1 OR v = 1 2172 ---- 2173 scalar-group-by 2174 ├── columns: count:5!null 2175 ├── cardinality: [1 - 1] 2176 ├── key: () 2177 ├── fd: ()-->(5) 2178 ├── project 2179 │ ├── columns: u:2 v:3 2180 │ └── distinct-on 2181 │ ├── columns: k:1!null u:2 v:3 2182 │ ├── grouping columns: k:1!null 2183 │ ├── key: (1) 2184 │ ├── fd: (1)-->(2,3) 2185 │ ├── union-all 2186 │ │ ├── columns: k:1!null u:2 v:3 2187 │ │ ├── left columns: k:1!null u:2 v:3 2188 │ │ ├── right columns: k:6 u:7 v:8 2189 │ │ ├── index-join d 2190 │ │ │ ├── columns: k:1!null u:2!null v:3 2191 │ │ │ ├── key: (1) 2192 │ │ │ ├── fd: ()-->(2), (1)-->(3) 2193 │ │ │ └── scan d@u 2194 │ │ │ ├── columns: k:1!null u:2!null 2195 │ │ │ ├── constraint: /2/1: [/1 - /1] 2196 │ │ │ ├── key: (1) 2197 │ │ │ └── fd: ()-->(2) 2198 │ │ └── index-join d 2199 │ │ ├── columns: k:6!null u:7 v:8!null 2200 │ │ ├── key: (6) 2201 │ │ ├── fd: ()-->(8), (6)-->(7) 2202 │ │ └── scan d@v 2203 │ │ ├── columns: k:6!null v:8!null 2204 │ │ ├── constraint: /8/6: [/1 - /1] 2205 │ │ ├── key: (6) 2206 │ │ └── fd: ()-->(8) 2207 │ └── aggregations 2208 │ ├── const-agg [as=u:2, outer=(2)] 2209 │ │ └── u:2 2210 │ └── const-agg [as=v:3, outer=(3)] 2211 │ └── v:3 2212 └── aggregations 2213 └── count-rows [as=count_rows:5] 2214 2215 2216 # Multi-column primary key. 2217 opt expect=SplitDisjunctionAddKey 2218 SELECT u, v FROM f WHERE u = 1 OR v = 2 2219 ---- 2220 project 2221 ├── columns: u:3 v:4 2222 └── distinct-on 2223 ├── columns: k:1!null j:2!null u:3 v:4 2224 ├── grouping columns: k:1!null j:2!null 2225 ├── key: (1,2) 2226 ├── fd: (1,2)-->(3,4) 2227 ├── union-all 2228 │ ├── columns: k:1!null j:2!null u:3 v:4 2229 │ ├── left columns: k:1!null j:2!null u:3 v:4 2230 │ ├── right columns: k:5 j:6 u:7 v:8 2231 │ ├── index-join f 2232 │ │ ├── columns: k:1!null j:2!null u:3!null v:4 2233 │ │ ├── key: (1,2) 2234 │ │ ├── fd: ()-->(3), (1,2)-->(4) 2235 │ │ └── scan f@u 2236 │ │ ├── columns: k:1!null j:2!null u:3!null 2237 │ │ ├── constraint: /3/1/2: [/1 - /1] 2238 │ │ ├── key: (1,2) 2239 │ │ └── fd: ()-->(3) 2240 │ └── index-join f 2241 │ ├── columns: k:5!null j:6!null u:7 v:8!null 2242 │ ├── key: (5,6) 2243 │ ├── fd: ()-->(8), (5,6)-->(7) 2244 │ └── scan f@v 2245 │ ├── columns: k:5!null j:6!null v:8!null 2246 │ ├── constraint: /8/5/6: [/2 - /2] 2247 │ ├── key: (5,6) 2248 │ └── fd: ()-->(8) 2249 └── aggregations 2250 ├── const-agg [as=u:3, outer=(3)] 2251 │ └── u:3 2252 └── const-agg [as=v:4, outer=(4)] 2253 └── v:4 2254 2255 # Don't expand INs to many ORs. 2256 opt expect=SplitDisjunctionAddKey 2257 SELECT u, v FROM d WHERE u IN (1, 2, 3, 4) OR v IN (5, 6, 7, 8) 2258 ---- 2259 project 2260 ├── columns: u:2 v:3 2261 └── distinct-on 2262 ├── columns: k:1!null u:2 v:3 2263 ├── grouping columns: k:1!null 2264 ├── key: (1) 2265 ├── fd: (1)-->(2,3) 2266 ├── union-all 2267 │ ├── columns: k:1!null u:2 v:3 2268 │ ├── left columns: k:1!null u:2 v:3 2269 │ ├── right columns: k:5 u:6 v:7 2270 │ ├── index-join d 2271 │ │ ├── columns: k:1!null u:2!null v:3 2272 │ │ ├── key: (1) 2273 │ │ ├── fd: (1)-->(2,3) 2274 │ │ └── scan d@u 2275 │ │ ├── columns: k:1!null u:2!null 2276 │ │ ├── constraint: /2/1: [/1 - /4] 2277 │ │ ├── key: (1) 2278 │ │ └── fd: (1)-->(2) 2279 │ └── index-join d 2280 │ ├── columns: k:5!null u:6 v:7!null 2281 │ ├── key: (5) 2282 │ ├── fd: (5)-->(6,7) 2283 │ └── scan d@v 2284 │ ├── columns: k:5!null v:7!null 2285 │ ├── constraint: /7/5: [/5 - /8] 2286 │ ├── key: (5) 2287 │ └── fd: (5)-->(7) 2288 └── aggregations 2289 ├── const-agg [as=u:2, outer=(2)] 2290 │ └── u:2 2291 └── const-agg [as=v:3, outer=(3)] 2292 └── v:3 2293 2294 # Split and constrain with an inverted index on JSONB on one side. 2295 opt expect=SplitDisjunctionAddKey 2296 SELECT u, j FROM b WHERE u = 1 OR j @> '{"foo": "bar"}' 2297 ---- 2298 project 2299 ├── columns: u:2 j:4 2300 └── distinct-on 2301 ├── columns: k:1!null u:2 j:4 2302 ├── grouping columns: k:1!null 2303 ├── key: (1) 2304 ├── fd: (1)-->(2,4) 2305 ├── union-all 2306 │ ├── columns: k:1!null u:2 j:4 2307 │ ├── left columns: k:1!null u:2 j:4 2308 │ ├── right columns: k:5 u:6 j:8 2309 │ ├── index-join b 2310 │ │ ├── columns: k:1!null u:2!null j:4 2311 │ │ ├── key: (1) 2312 │ │ ├── fd: ()-->(2), (1)-->(4) 2313 │ │ └── scan b@u 2314 │ │ ├── columns: k:1!null u:2!null 2315 │ │ ├── constraint: /2/1: [/1 - /1] 2316 │ │ ├── key: (1) 2317 │ │ └── fd: ()-->(2) 2318 │ └── index-join b 2319 │ ├── columns: k:5!null u:6 j:8 2320 │ ├── key: (5) 2321 │ ├── fd: (5)-->(6,8) 2322 │ └── scan b@inv_idx 2323 │ ├── columns: k:5!null 2324 │ ├── constraint: /8/5: [/'{"foo": "bar"}' - /'{"foo": "bar"}'] 2325 │ └── key: (5) 2326 └── aggregations 2327 ├── const-agg [as=u:2, outer=(2)] 2328 │ └── u:2 2329 └── const-agg [as=j:4, outer=(4)] 2330 └── j:4 2331 2332 # Split and constrain with an inverted index on an array on one side. 2333 opt expect=SplitDisjunctionAddKey 2334 SELECT u, a FROM c WHERE u = 1 OR a @> ARRAY[2] 2335 ---- 2336 project 2337 ├── columns: u:3 a:2 2338 └── distinct-on 2339 ├── columns: k:1!null a:2 u:3 2340 ├── grouping columns: k:1!null 2341 ├── key: (1) 2342 ├── fd: (1)-->(2,3) 2343 ├── union-all 2344 │ ├── columns: k:1!null a:2 u:3 2345 │ ├── left columns: k:1!null a:2 u:3 2346 │ ├── right columns: k:4 a:5 u:6 2347 │ ├── index-join c 2348 │ │ ├── columns: k:1!null a:2 u:3!null 2349 │ │ ├── key: (1) 2350 │ │ ├── fd: ()-->(3), (1)-->(2) 2351 │ │ └── scan c@u 2352 │ │ ├── columns: k:1!null u:3!null 2353 │ │ ├── constraint: /3/1: [/1 - /1] 2354 │ │ ├── key: (1) 2355 │ │ └── fd: ()-->(3) 2356 │ └── index-join c 2357 │ ├── columns: k:4!null a:5 u:6 2358 │ ├── key: (4) 2359 │ ├── fd: (4)-->(5,6) 2360 │ └── scan c@inv_idx 2361 │ ├── columns: k:4!null 2362 │ ├── constraint: /5/4: [/ARRAY[2] - /ARRAY[2]] 2363 │ └── key: (4) 2364 └── aggregations 2365 ├── const-agg [as=a:2, outer=(2)] 2366 │ └── a:2 2367 └── const-agg [as=u:3, outer=(3)] 2368 └── u:3 2369 2370 # Uncorrelated subquery. 2371 opt expect=SplitDisjunctionAddKey 2372 SELECT u, v FROM d WHERE (u = 1 OR v = 1) AND EXISTS (SELECT u, v FROM a) 2373 ---- 2374 project 2375 ├── columns: u:2 v:3 2376 └── distinct-on 2377 ├── columns: d.k:1!null d.u:2 d.v:3 2378 ├── grouping columns: d.k:1!null 2379 ├── key: (1) 2380 ├── fd: (1)-->(2,3) 2381 ├── union-all 2382 │ ├── columns: d.k:1!null d.u:2 d.v:3 2383 │ ├── left columns: d.k:1!null d.u:2 d.v:3 2384 │ ├── right columns: d.k:8 d.u:9 d.v:10 2385 │ ├── index-join d 2386 │ │ ├── columns: d.k:1!null d.u:2!null d.v:3 2387 │ │ ├── key: (1) 2388 │ │ ├── fd: ()-->(2), (1)-->(3) 2389 │ │ └── select 2390 │ │ ├── columns: d.k:1!null d.u:2!null 2391 │ │ ├── key: (1) 2392 │ │ ├── fd: ()-->(2) 2393 │ │ ├── scan d@u 2394 │ │ │ ├── columns: d.k:1!null d.u:2!null 2395 │ │ │ ├── constraint: /2/1: [/1 - /1] 2396 │ │ │ ├── key: (1) 2397 │ │ │ └── fd: ()-->(2) 2398 │ │ └── filters 2399 │ │ └── exists [subquery] 2400 │ │ └── scan a 2401 │ │ ├── columns: a.u:6 a.v:7 2402 │ │ ├── limit: 1 2403 │ │ ├── key: () 2404 │ │ └── fd: ()-->(6,7) 2405 │ └── index-join d 2406 │ ├── columns: d.k:8!null d.u:9 d.v:10!null 2407 │ ├── key: (8) 2408 │ ├── fd: ()-->(10), (8)-->(9) 2409 │ └── select 2410 │ ├── columns: d.k:8!null d.v:10!null 2411 │ ├── key: (8) 2412 │ ├── fd: ()-->(10) 2413 │ ├── scan d@v 2414 │ │ ├── columns: d.k:8!null d.v:10!null 2415 │ │ ├── constraint: /10/8: [/1 - /1] 2416 │ │ ├── key: (8) 2417 │ │ └── fd: ()-->(10) 2418 │ └── filters 2419 │ └── exists [subquery] 2420 │ └── scan a 2421 │ ├── columns: a.u:6 a.v:7 2422 │ ├── limit: 1 2423 │ ├── key: () 2424 │ └── fd: ()-->(6,7) 2425 └── aggregations 2426 ├── const-agg [as=d.u:2, outer=(2)] 2427 │ └── d.u:2 2428 └── const-agg [as=d.v:3, outer=(3)] 2429 └── d.v:3 2430 2431 # Correlated subquery. 2432 opt expect=SplitDisjunctionAddKey 2433 SELECT u, v FROM d WHERE (u = 1 OR v = 1) AND EXISTS (SELECT * FROM a WHERE a.u = d.u) 2434 ---- 2435 project 2436 ├── columns: u:2 v:3 2437 └── inner-join (hash) 2438 ├── columns: d.u:2!null d.v:3 a.u:6!null 2439 ├── fd: (2)==(6), (6)==(2) 2440 ├── project 2441 │ ├── columns: d.u:2 d.v:3 2442 │ └── distinct-on 2443 │ ├── columns: d.k:1!null d.u:2 d.v:3 2444 │ ├── grouping columns: d.k:1!null 2445 │ ├── key: (1) 2446 │ ├── fd: (1)-->(2,3) 2447 │ ├── union-all 2448 │ │ ├── columns: d.k:1!null d.u:2 d.v:3 2449 │ │ ├── left columns: d.k:1!null d.u:2 d.v:3 2450 │ │ ├── right columns: d.k:8 d.u:9 d.v:10 2451 │ │ ├── index-join d 2452 │ │ │ ├── columns: d.k:1!null d.u:2!null d.v:3 2453 │ │ │ ├── key: (1) 2454 │ │ │ ├── fd: ()-->(2), (1)-->(3) 2455 │ │ │ └── scan d@u 2456 │ │ │ ├── columns: d.k:1!null d.u:2!null 2457 │ │ │ ├── constraint: /2/1: [/1 - /1] 2458 │ │ │ ├── key: (1) 2459 │ │ │ └── fd: ()-->(2) 2460 │ │ └── index-join d 2461 │ │ ├── columns: d.k:8!null d.u:9 d.v:10!null 2462 │ │ ├── key: (8) 2463 │ │ ├── fd: ()-->(10), (8)-->(9) 2464 │ │ └── scan d@v 2465 │ │ ├── columns: d.k:8!null d.v:10!null 2466 │ │ ├── constraint: /10/8: [/1 - /1] 2467 │ │ ├── key: (8) 2468 │ │ └── fd: ()-->(10) 2469 │ └── aggregations 2470 │ ├── const-agg [as=d.u:2, outer=(2)] 2471 │ │ └── d.u:2 2472 │ └── const-agg [as=d.v:3, outer=(3)] 2473 │ └── d.v:3 2474 ├── distinct-on 2475 │ ├── columns: a.u:6 2476 │ ├── grouping columns: a.u:6 2477 │ ├── internal-ordering: +6 2478 │ ├── key: (6) 2479 │ └── scan a@u 2480 │ ├── columns: a.u:6 2481 │ └── ordering: +6 2482 └── filters 2483 └── a.u:6 = d.u:2 [outer=(2,6), constraints=(/2: (/NULL - ]; /6: (/NULL - ]), fd=(2)==(6), (6)==(2)] 2484 2485 # Correlated subquery with references to outer columns not in the scan columns. 2486 opt expect=SplitDisjunctionAddKey 2487 SELECT u, v FROM d WHERE (u = 1 OR v = 1) AND EXISTS (SELECT * FROM a WHERE a.u = d.w) 2488 ---- 2489 project 2490 ├── columns: u:2 v:3 2491 └── project 2492 ├── columns: d.u:2 d.v:3 w:4 2493 └── inner-join (hash) 2494 ├── columns: d.u:2 d.v:3 w:4!null a.u:6!null 2495 ├── fd: (4)==(6), (6)==(4) 2496 ├── project 2497 │ ├── columns: d.u:2 d.v:3 w:4 2498 │ └── distinct-on 2499 │ ├── columns: d.k:1!null d.u:2 d.v:3 w:4 2500 │ ├── grouping columns: d.k:1!null 2501 │ ├── key: (1) 2502 │ ├── fd: (1)-->(2-4) 2503 │ ├── union-all 2504 │ │ ├── columns: d.k:1!null d.u:2 d.v:3 w:4 2505 │ │ ├── left columns: d.k:1!null d.u:2 d.v:3 w:4 2506 │ │ ├── right columns: d.k:8 d.u:9 d.v:10 w:11 2507 │ │ ├── index-join d 2508 │ │ │ ├── columns: d.k:1!null d.u:2!null d.v:3 w:4 2509 │ │ │ ├── key: (1) 2510 │ │ │ ├── fd: ()-->(2), (1)-->(3,4) 2511 │ │ │ └── scan d@u 2512 │ │ │ ├── columns: d.k:1!null d.u:2!null 2513 │ │ │ ├── constraint: /2/1: [/1 - /1] 2514 │ │ │ ├── key: (1) 2515 │ │ │ └── fd: ()-->(2) 2516 │ │ └── index-join d 2517 │ │ ├── columns: d.k:8!null d.u:9 d.v:10!null w:11 2518 │ │ ├── key: (8) 2519 │ │ ├── fd: ()-->(10), (8)-->(9,11) 2520 │ │ └── scan d@v 2521 │ │ ├── columns: d.k:8!null d.v:10!null 2522 │ │ ├── constraint: /10/8: [/1 - /1] 2523 │ │ ├── key: (8) 2524 │ │ └── fd: ()-->(10) 2525 │ └── aggregations 2526 │ ├── const-agg [as=d.u:2, outer=(2)] 2527 │ │ └── d.u:2 2528 │ ├── const-agg [as=d.v:3, outer=(3)] 2529 │ │ └── d.v:3 2530 │ └── const-agg [as=w:4, outer=(4)] 2531 │ └── w:4 2532 ├── distinct-on 2533 │ ├── columns: a.u:6 2534 │ ├── grouping columns: a.u:6 2535 │ ├── internal-ordering: +6 2536 │ ├── key: (6) 2537 │ └── scan a@u 2538 │ ├── columns: a.u:6 2539 │ └── ordering: +6 2540 └── filters 2541 └── a.u:6 = w:4 [outer=(4,6), constraints=(/4: (/NULL - ]; /6: (/NULL - ]), fd=(4)==(6), (6)==(4)] 2542 2543 # Use rowid when there is no explicit primary key. 2544 opt expect=SplitDisjunctionAddKey 2545 SELECT u, v FROM no_explicit_primary_key WHERE u = 1 OR v = 5 2546 ---- 2547 project 2548 ├── columns: u:2 v:3 2549 └── distinct-on 2550 ├── columns: u:2 v:3 rowid:4!null 2551 ├── grouping columns: rowid:4!null 2552 ├── key: (4) 2553 ├── fd: (4)-->(2,3) 2554 ├── union-all 2555 │ ├── columns: u:2 v:3 rowid:4!null 2556 │ ├── left columns: u:2 v:3 rowid:4!null 2557 │ ├── right columns: u:6 v:7 rowid:8 2558 │ ├── index-join no_explicit_primary_key 2559 │ │ ├── columns: u:2!null v:3 rowid:4!null 2560 │ │ ├── key: (4) 2561 │ │ ├── fd: ()-->(2), (4)-->(3) 2562 │ │ └── scan no_explicit_primary_key@u 2563 │ │ ├── columns: u:2!null rowid:4!null 2564 │ │ ├── constraint: /2/4: [/1 - /1] 2565 │ │ ├── key: (4) 2566 │ │ └── fd: ()-->(2) 2567 │ └── index-join no_explicit_primary_key 2568 │ ├── columns: u:6 v:7!null rowid:8!null 2569 │ ├── key: (8) 2570 │ ├── fd: ()-->(7), (8)-->(6) 2571 │ └── scan no_explicit_primary_key@v 2572 │ ├── columns: v:7!null rowid:8!null 2573 │ ├── constraint: /7/8: [/5 - /5] 2574 │ ├── key: (8) 2575 │ └── fd: ()-->(7) 2576 └── aggregations 2577 ├── const-agg [as=u:2, outer=(2)] 2578 │ └── u:2 2579 └── const-agg [as=v:3, outer=(3)] 2580 └── v:3 2581 2582 # Apply when outer columns of both sides of OR are a subset of index columns. 2583 opt expect=SplitDisjunctionAddKey 2584 SELECT u, v FROM e WHERE u = 1 OR v = 1 2585 ---- 2586 project 2587 ├── columns: u:2 v:3 2588 └── distinct-on 2589 ├── columns: k:1!null u:2 v:3 2590 ├── grouping columns: k:1!null 2591 ├── key: (1) 2592 ├── fd: (1)-->(2,3) 2593 ├── union-all 2594 │ ├── columns: k:1!null u:2 v:3 2595 │ ├── left columns: k:1!null u:2 v:3 2596 │ ├── right columns: k:5 u:6 v:7 2597 │ ├── index-join e 2598 │ │ ├── columns: k:1!null u:2!null v:3 2599 │ │ ├── key: (1) 2600 │ │ ├── fd: ()-->(2), (1)-->(3) 2601 │ │ └── scan e@uw 2602 │ │ ├── columns: k:1!null u:2!null 2603 │ │ ├── constraint: /2/4/1: [/1 - /1] 2604 │ │ ├── key: (1) 2605 │ │ └── fd: ()-->(2) 2606 │ └── index-join e 2607 │ ├── columns: k:5!null u:6 v:7!null 2608 │ ├── key: (5) 2609 │ ├── fd: ()-->(7), (5)-->(6) 2610 │ └── scan e@vw 2611 │ ├── columns: k:5!null v:7!null 2612 │ ├── constraint: /7/8/5: [/1 - /1] 2613 │ ├── key: (5) 2614 │ └── fd: ()-->(7) 2615 └── aggregations 2616 ├── const-agg [as=u:2, outer=(2)] 2617 │ └── u:2 2618 └── const-agg [as=v:3, outer=(3)] 2619 └── v:3 2620 2621 # Apply when outer columns of both sides of OR are a superset of index columns. 2622 opt expect=SplitDisjunctionAddKey 2623 SELECT u, v FROM d WHERE (u = 1 AND w = 2) OR (v = 1 AND w = 3) 2624 ---- 2625 project 2626 ├── columns: u:2 v:3 2627 └── project 2628 ├── columns: u:2 v:3 w:4!null 2629 └── distinct-on 2630 ├── columns: k:1!null u:2 v:3 w:4!null 2631 ├── grouping columns: k:1!null 2632 ├── key: (1) 2633 ├── fd: (1)-->(2-4) 2634 ├── union-all 2635 │ ├── columns: k:1!null u:2 v:3 w:4!null 2636 │ ├── left columns: k:1!null u:2 v:3 w:4!null 2637 │ ├── right columns: k:5 u:6 v:7 w:8 2638 │ ├── select 2639 │ │ ├── columns: k:1!null u:2!null v:3 w:4!null 2640 │ │ ├── key: (1) 2641 │ │ ├── fd: ()-->(2,4), (1)-->(3) 2642 │ │ ├── index-join d 2643 │ │ │ ├── columns: k:1!null u:2 v:3 w:4 2644 │ │ │ ├── key: (1) 2645 │ │ │ ├── fd: ()-->(2), (1)-->(3,4) 2646 │ │ │ └── scan d@u 2647 │ │ │ ├── columns: k:1!null u:2!null 2648 │ │ │ ├── constraint: /2/1: [/1 - /1] 2649 │ │ │ ├── key: (1) 2650 │ │ │ └── fd: ()-->(2) 2651 │ │ └── filters 2652 │ │ └── w:4 = 2 [outer=(4), constraints=(/4: [/2 - /2]; tight), fd=()-->(4)] 2653 │ └── select 2654 │ ├── columns: k:5!null u:6 v:7!null w:8!null 2655 │ ├── key: (5) 2656 │ ├── fd: ()-->(7,8), (5)-->(6) 2657 │ ├── index-join d 2658 │ │ ├── columns: k:5!null u:6 v:7 w:8 2659 │ │ ├── key: (5) 2660 │ │ ├── fd: ()-->(7), (5)-->(6,8) 2661 │ │ └── scan d@v 2662 │ │ ├── columns: k:5!null v:7!null 2663 │ │ ├── constraint: /7/5: [/1 - /1] 2664 │ │ ├── key: (5) 2665 │ │ └── fd: ()-->(7) 2666 │ └── filters 2667 │ └── w:8 = 3 [outer=(8), constraints=(/8: [/3 - /3]; tight), fd=()-->(8)] 2668 └── aggregations 2669 ├── const-agg [as=u:2, outer=(2)] 2670 │ └── u:2 2671 ├── const-agg [as=v:3, outer=(3)] 2672 │ └── v:3 2673 └── const-agg [as=w:4, outer=(4)] 2674 └── w:4 2675 2676 # Group sub-expr with the same columns together. 2677 opt expect=SplitDisjunctionAddKey 2678 SELECT u, v FROM d WHERE (u = 1 OR v = 2) OR (u = 3 OR v = 4) 2679 ---- 2680 project 2681 ├── columns: u:2 v:3 2682 └── distinct-on 2683 ├── columns: k:1!null u:2 v:3 2684 ├── grouping columns: k:1!null 2685 ├── key: (1) 2686 ├── fd: (1)-->(2,3) 2687 ├── union-all 2688 │ ├── columns: k:1!null u:2 v:3 2689 │ ├── left columns: k:1!null u:2 v:3 2690 │ ├── right columns: k:5 u:6 v:7 2691 │ ├── index-join d 2692 │ │ ├── columns: k:1!null u:2!null v:3 2693 │ │ ├── key: (1) 2694 │ │ ├── fd: (1)-->(2,3) 2695 │ │ └── scan d@u 2696 │ │ ├── columns: k:1!null u:2!null 2697 │ │ ├── constraint: /2/1 2698 │ │ │ ├── [/1 - /1] 2699 │ │ │ └── [/3 - /3] 2700 │ │ ├── key: (1) 2701 │ │ └── fd: (1)-->(2) 2702 │ └── index-join d 2703 │ ├── columns: k:5!null u:6 v:7!null 2704 │ ├── key: (5) 2705 │ ├── fd: (5)-->(6,7) 2706 │ └── scan d@v 2707 │ ├── columns: k:5!null v:7!null 2708 │ ├── constraint: /7/5 2709 │ │ ├── [/2 - /2] 2710 │ │ └── [/4 - /4] 2711 │ ├── key: (5) 2712 │ └── fd: (5)-->(7) 2713 └── aggregations 2714 ├── const-agg [as=u:2, outer=(2)] 2715 │ └── u:2 2716 └── const-agg [as=v:3, outer=(3)] 2717 └── v:3 2718 2719 # Group sub-expr with the same columns together. Output should have a single union expr. 2720 opt expect=SplitDisjunctionAddKey 2721 SELECT u, v FROM d WHERE u = 1 OR u = 3 OR v = 2 OR v = 4 OR u = 5 OR v = 6 2722 ---- 2723 project 2724 ├── columns: u:2 v:3 2725 └── distinct-on 2726 ├── columns: k:1!null u:2 v:3 2727 ├── grouping columns: k:1!null 2728 ├── key: (1) 2729 ├── fd: (1)-->(2,3) 2730 ├── union-all 2731 │ ├── columns: k:1!null u:2 v:3 2732 │ ├── left columns: k:1!null u:2 v:3 2733 │ ├── right columns: k:5 u:6 v:7 2734 │ ├── index-join d 2735 │ │ ├── columns: k:1!null u:2!null v:3 2736 │ │ ├── key: (1) 2737 │ │ ├── fd: (1)-->(2,3) 2738 │ │ └── scan d@u 2739 │ │ ├── columns: k:1!null u:2!null 2740 │ │ ├── constraint: /2/1 2741 │ │ │ ├── [/1 - /1] 2742 │ │ │ ├── [/3 - /3] 2743 │ │ │ └── [/5 - /5] 2744 │ │ ├── key: (1) 2745 │ │ └── fd: (1)-->(2) 2746 │ └── index-join d 2747 │ ├── columns: k:5!null u:6 v:7!null 2748 │ ├── key: (5) 2749 │ ├── fd: (5)-->(6,7) 2750 │ └── scan d@v 2751 │ ├── columns: k:5!null v:7!null 2752 │ ├── constraint: /7/5 2753 │ │ ├── [/2 - /2] 2754 │ │ ├── [/4 - /4] 2755 │ │ └── [/6 - /6] 2756 │ ├── key: (5) 2757 │ └── fd: (5)-->(7) 2758 └── aggregations 2759 ├── const-agg [as=u:2, outer=(2)] 2760 │ └── u:2 2761 └── const-agg [as=v:3, outer=(3)] 2762 └── v:3 2763 2764 # Group sub-expr with the same columns together. Output should have a single union expr. 2765 opt expect=SplitDisjunctionAddKey 2766 SELECT u, v FROM d WHERE (u = 3 OR v = 2) OR (u = 5 OR v = 4) OR v = 6 2767 ---- 2768 project 2769 ├── columns: u:2 v:3 2770 └── distinct-on 2771 ├── columns: k:1!null u:2 v:3 2772 ├── grouping columns: k:1!null 2773 ├── key: (1) 2774 ├── fd: (1)-->(2,3) 2775 ├── union-all 2776 │ ├── columns: k:1!null u:2 v:3 2777 │ ├── left columns: k:1!null u:2 v:3 2778 │ ├── right columns: k:5 u:6 v:7 2779 │ ├── index-join d 2780 │ │ ├── columns: k:1!null u:2!null v:3 2781 │ │ ├── key: (1) 2782 │ │ ├── fd: (1)-->(2,3) 2783 │ │ └── scan d@u 2784 │ │ ├── columns: k:1!null u:2!null 2785 │ │ ├── constraint: /2/1 2786 │ │ │ ├── [/3 - /3] 2787 │ │ │ └── [/5 - /5] 2788 │ │ ├── key: (1) 2789 │ │ └── fd: (1)-->(2) 2790 │ └── index-join d 2791 │ ├── columns: k:5!null u:6 v:7!null 2792 │ ├── key: (5) 2793 │ ├── fd: (5)-->(6,7) 2794 │ └── scan d@v 2795 │ ├── columns: k:5!null v:7!null 2796 │ ├── constraint: /7/5 2797 │ │ ├── [/2 - /2] 2798 │ │ ├── [/4 - /4] 2799 │ │ └── [/6 - /6] 2800 │ ├── key: (5) 2801 │ └── fd: (5)-->(7) 2802 └── aggregations 2803 ├── const-agg [as=u:2, outer=(2)] 2804 │ └── u:2 2805 └── const-agg [as=v:3, outer=(3)] 2806 └── v:3 2807 2808 # Find the first disjunction in the filters that have different column sets on 2809 # the left and right. 2810 opt expect=SplitDisjunctionAddKey 2811 SELECT u, v FROM d WHERE (w = 1 OR w = 2) AND (u = 3 OR v = 4) 2812 ---- 2813 project 2814 ├── columns: u:2 v:3 2815 └── project 2816 ├── columns: u:2 v:3 w:4!null 2817 └── distinct-on 2818 ├── columns: k:1!null u:2 v:3 w:4!null 2819 ├── grouping columns: k:1!null 2820 ├── key: (1) 2821 ├── fd: (1)-->(2-4) 2822 ├── union-all 2823 │ ├── columns: k:1!null u:2 v:3 w:4!null 2824 │ ├── left columns: k:1!null u:2 v:3 w:4!null 2825 │ ├── right columns: k:5 u:6 v:7 w:8 2826 │ ├── select 2827 │ │ ├── columns: k:1!null u:2!null v:3 w:4!null 2828 │ │ ├── key: (1) 2829 │ │ ├── fd: ()-->(2), (1)-->(3,4) 2830 │ │ ├── index-join d 2831 │ │ │ ├── columns: k:1!null u:2 v:3 w:4 2832 │ │ │ ├── key: (1) 2833 │ │ │ ├── fd: ()-->(2), (1)-->(3,4) 2834 │ │ │ └── scan d@u 2835 │ │ │ ├── columns: k:1!null u:2!null 2836 │ │ │ ├── constraint: /2/1: [/3 - /3] 2837 │ │ │ ├── key: (1) 2838 │ │ │ └── fd: ()-->(2) 2839 │ │ └── filters 2840 │ │ └── (w:4 = 1) OR (w:4 = 2) [outer=(4), constraints=(/4: [/1 - /1] [/2 - /2]; tight)] 2841 │ └── select 2842 │ ├── columns: k:5!null u:6 v:7!null w:8!null 2843 │ ├── key: (5) 2844 │ ├── fd: ()-->(7), (5)-->(6,8) 2845 │ ├── index-join d 2846 │ │ ├── columns: k:5!null u:6 v:7 w:8 2847 │ │ ├── key: (5) 2848 │ │ ├── fd: ()-->(7), (5)-->(6,8) 2849 │ │ └── scan d@v 2850 │ │ ├── columns: k:5!null v:7!null 2851 │ │ ├── constraint: /7/5: [/4 - /4] 2852 │ │ ├── key: (5) 2853 │ │ └── fd: ()-->(7) 2854 │ └── filters 2855 │ └── (w:8 = 1) OR (w:8 = 2) [outer=(8), constraints=(/8: [/1 - /1] [/2 - /2]; tight)] 2856 └── aggregations 2857 ├── const-agg [as=u:2, outer=(2)] 2858 │ └── u:2 2859 ├── const-agg [as=v:3, outer=(3)] 2860 │ └── v:3 2861 └── const-agg [as=w:4, outer=(4)] 2862 └── w:4 2863 2864 # Find the first disjunction in the filters that have columns on the left and 2865 # right that constrain a scan. 2866 opt expect=SplitDisjunctionAddKey 2867 SELECT u, v FROM d WHERE (u = 1 OR w = 2) AND (u = 3 OR v = 4) 2868 ---- 2869 project 2870 ├── columns: u:2 v:3 2871 └── project 2872 ├── columns: u:2 v:3 w:4 2873 └── distinct-on 2874 ├── columns: k:1!null u:2 v:3 w:4 2875 ├── grouping columns: k:1!null 2876 ├── key: (1) 2877 ├── fd: (1)-->(2-4) 2878 ├── union-all 2879 │ ├── columns: k:1!null u:2 v:3 w:4 2880 │ ├── left columns: k:1!null u:2 v:3 w:4 2881 │ ├── right columns: k:5 u:6 v:7 w:8 2882 │ ├── select 2883 │ │ ├── columns: k:1!null u:2!null v:3 w:4!null 2884 │ │ ├── key: (1) 2885 │ │ ├── fd: ()-->(2,4), (1)-->(3) 2886 │ │ ├── index-join d 2887 │ │ │ ├── columns: k:1!null u:2 v:3 w:4 2888 │ │ │ ├── key: (1) 2889 │ │ │ ├── fd: ()-->(2), (1)-->(3,4) 2890 │ │ │ └── scan d@u 2891 │ │ │ ├── columns: k:1!null u:2!null 2892 │ │ │ ├── constraint: /2/1: [/3 - /3] 2893 │ │ │ ├── key: (1) 2894 │ │ │ └── fd: ()-->(2) 2895 │ │ └── filters 2896 │ │ └── w:4 = 2 [outer=(4), constraints=(/4: [/2 - /2]; tight), fd=()-->(4)] 2897 │ └── select 2898 │ ├── columns: k:5!null u:6 v:7!null w:8 2899 │ ├── key: (5) 2900 │ ├── fd: ()-->(7), (5)-->(6,8) 2901 │ ├── index-join d 2902 │ │ ├── columns: k:5!null u:6 v:7 w:8 2903 │ │ ├── key: (5) 2904 │ │ ├── fd: ()-->(7), (5)-->(6,8) 2905 │ │ └── scan d@v 2906 │ │ ├── columns: k:5!null v:7!null 2907 │ │ ├── constraint: /7/5: [/4 - /4] 2908 │ │ ├── key: (5) 2909 │ │ └── fd: ()-->(7) 2910 │ └── filters 2911 │ └── (u:6 = 1) OR (w:8 = 2) [outer=(6,8)] 2912 └── aggregations 2913 ├── const-agg [as=u:2, outer=(2)] 2914 │ └── u:2 2915 ├── const-agg [as=v:3, outer=(3)] 2916 │ └── v:3 2917 └── const-agg [as=w:4, outer=(4)] 2918 └── w:4 2919 2920 # Don't apply when outer columns of both sides of OR do not intersect with index columns. 2921 opt expect-not=SplitDisjunctionAddKey 2922 SELECT u, w FROM d WHERE u = 1 OR w = 1 2923 ---- 2924 select 2925 ├── columns: u:2 w:4 2926 ├── scan d 2927 │ └── columns: u:2 w:4 2928 └── filters 2929 └── (u:2 = 1) OR (w:4 = 1) [outer=(2,4)] 2930 2931 # Don't apply to queries with strict keys. 2932 opt expect-not=SplitDisjunctionAddKey 2933 SELECT k, u, v FROM d WHERE u = 1 OR v = 1 2934 ---- 2935 distinct-on 2936 ├── columns: k:1!null u:2 v:3 2937 ├── grouping columns: k:1!null 2938 ├── key: (1) 2939 ├── fd: (1)-->(2,3) 2940 ├── union-all 2941 │ ├── columns: k:1!null u:2 v:3 2942 │ ├── left columns: k:1!null u:2 v:3 2943 │ ├── right columns: k:5 u:6 v:7 2944 │ ├── index-join d 2945 │ │ ├── columns: k:1!null u:2!null v:3 2946 │ │ ├── key: (1) 2947 │ │ ├── fd: ()-->(2), (1)-->(3) 2948 │ │ └── scan d@u 2949 │ │ ├── columns: k:1!null u:2!null 2950 │ │ ├── constraint: /2/1: [/1 - /1] 2951 │ │ ├── key: (1) 2952 │ │ └── fd: ()-->(2) 2953 │ └── index-join d 2954 │ ├── columns: k:5!null u:6 v:7!null 2955 │ ├── key: (5) 2956 │ ├── fd: ()-->(7), (5)-->(6) 2957 │ └── scan d@v 2958 │ ├── columns: k:5!null v:7!null 2959 │ ├── constraint: /7/5: [/1 - /1] 2960 │ ├── key: (5) 2961 │ └── fd: ()-->(7) 2962 └── aggregations 2963 ├── const-agg [as=u:2, outer=(2)] 2964 │ └── u:2 2965 └── const-agg [as=v:3, outer=(3)] 2966 └── v:3 2967 2968 # Don't apply to disjunctions with identical colsets on the left and right. 2969 opt expect-not=SplitDisjunctionAddKey 2970 SELECT u FROM d WHERE u = 1 OR u = 5 2971 ---- 2972 scan d@u 2973 ├── columns: u:2!null 2974 └── constraint: /2/1 2975 ├── [/1 - /1] 2976 └── [/5 - /5] 2977 2978 # Verifies that flags are copied to the duplicated scan. 2979 opt expect=SplitDisjunctionAddKey 2980 SELECT u, v FROM a@{NO_INDEX_JOIN} WHERE u = 1 OR v = 1 2981 ---- 2982 project 2983 ├── columns: u:2 v:3 2984 ├── lax-key: (2,3) 2985 ├── fd: (3)~~>(2) 2986 └── distinct-on 2987 ├── columns: k:1!null u:2 v:3 2988 ├── grouping columns: k:1!null 2989 ├── key: (1) 2990 ├── fd: (1)-->(2,3) 2991 ├── union-all 2992 │ ├── columns: k:1!null u:2 v:3 2993 │ ├── left columns: k:1!null u:2 v:3 2994 │ ├── right columns: k:4 u:5 v:6 2995 │ ├── scan a@u 2996 │ │ ├── columns: k:1!null u:2!null v:3 2997 │ │ ├── constraint: /2/1: [/1 - /1] 2998 │ │ ├── flags: no-index-join 2999 │ │ ├── key: (1) 3000 │ │ └── fd: ()-->(2), (1)-->(3), (3)~~>(1) 3001 │ └── scan a@v 3002 │ ├── columns: k:4!null u:5 v:6!null 3003 │ ├── constraint: /6: [/1 - /1] 3004 │ ├── flags: no-index-join 3005 │ ├── cardinality: [0 - 1] 3006 │ ├── key: () 3007 │ └── fd: ()-->(4-6) 3008 └── aggregations 3009 ├── const-agg [as=u:2, outer=(2)] 3010 │ └── u:2 3011 └── const-agg [as=v:3, outer=(3)] 3012 └── v:3 3013 3014 # Columns are passed-through correctly when EliminateUnionAllLeft is applied. 3015 opt expect=SplitDisjunctionAddKey 3016 SELECT u, v FROM d WHERE u = 2 OR (v = 1 AND v = 3) 3017 ---- 3018 project 3019 ├── columns: u:2!null v:3 3020 ├── fd: ()-->(2) 3021 └── index-join d 3022 ├── columns: k:1!null u:2!null v:3 3023 ├── key: (1) 3024 ├── fd: ()-->(2), (1)-->(3) 3025 └── scan d@u 3026 ├── columns: k:1!null u:2!null 3027 ├── constraint: /2/1: [/2 - /2] 3028 ├── key: (1) 3029 └── fd: ()-->(2)