github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/norm/testdata/rules/limit (about) 1 exec-ddl 2 CREATE TABLE a (k INT PRIMARY KEY, i INT, f FLOAT, s STRING, j JSON) 3 ---- 4 5 exec-ddl 6 CREATE TABLE b (x INT PRIMARY KEY, y INT) 7 ---- 8 9 exec-ddl 10 CREATE TABLE ab (a INT PRIMARY KEY, b INT) 11 ---- 12 13 exec-ddl 14 CREATE TABLE uv (u INT PRIMARY KEY, v INT) 15 ---- 16 17 # -------------------------------------------------- 18 # EliminateLimit 19 # -------------------------------------------------- 20 norm expect=EliminateLimit 21 SELECT * FROM (SELECT * FROM a LIMIT 99) LIMIT 100 22 ---- 23 limit 24 ├── columns: k:1!null i:2 f:3 s:4 j:5 25 ├── cardinality: [0 - 99] 26 ├── key: (1) 27 ├── fd: (1)-->(2-5) 28 ├── scan a 29 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 30 │ ├── key: (1) 31 │ ├── fd: (1)-->(2-5) 32 │ └── limit hint: 99.00 33 └── 99 34 35 norm expect=EliminateLimit 36 SELECT * FROM (SELECT * FROM a LIMIT 100) LIMIT 100 37 ---- 38 limit 39 ├── columns: k:1!null i:2 f:3 s:4 j:5 40 ├── cardinality: [0 - 100] 41 ├── key: (1) 42 ├── fd: (1)-->(2-5) 43 ├── scan a 44 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 45 │ ├── key: (1) 46 │ ├── fd: (1)-->(2-5) 47 │ └── limit hint: 100.00 48 └── 100 49 50 # Don't eliminate the outer limit if it's less than the inner. 51 norm 52 SELECT * FROM (SELECT * FROM a LIMIT 100) LIMIT 99 53 ---- 54 limit 55 ├── columns: k:1!null i:2 f:3 s:4 j:5 56 ├── cardinality: [0 - 99] 57 ├── key: (1) 58 ├── fd: (1)-->(2-5) 59 ├── limit 60 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 61 │ ├── cardinality: [0 - 100] 62 │ ├── key: (1) 63 │ ├── fd: (1)-->(2-5) 64 │ ├── limit hint: 99.00 65 │ ├── scan a 66 │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 67 │ │ ├── key: (1) 68 │ │ ├── fd: (1)-->(2-5) 69 │ │ └── limit hint: 100.00 70 │ └── 100 71 └── 99 72 73 # High limits (> max uint32), can't eliminate in this case. 74 norm 75 SELECT * FROM (SELECT * FROM a LIMIT 5000000000) LIMIT 5100000000 76 ---- 77 limit 78 ├── columns: k:1!null i:2 f:3 s:4 j:5 79 ├── key: (1) 80 ├── fd: (1)-->(2-5) 81 ├── limit 82 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 83 │ ├── key: (1) 84 │ ├── fd: (1)-->(2-5) 85 │ ├── limit hint: 5100000000.00 86 │ ├── scan a 87 │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 88 │ │ ├── key: (1) 89 │ │ ├── fd: (1)-->(2-5) 90 │ │ └── limit hint: 5000000000.00 91 │ └── 5000000000 92 └── 5100000000 93 94 # Don't eliminate in case of negative limit. 95 norm 96 SELECT * FROM (SELECT * FROM a LIMIT 0) LIMIT -1 97 ---- 98 limit 99 ├── columns: k:1!null i:2!null f:3!null s:4!null j:5!null 100 ├── cardinality: [0 - 0] 101 ├── immutable, side-effects 102 ├── key: () 103 ├── fd: ()-->(1-5) 104 ├── values 105 │ ├── columns: k:1!null i:2!null f:3!null s:4!null j:5!null 106 │ ├── cardinality: [0 - 0] 107 │ ├── key: () 108 │ ├── fd: ()-->(1-5) 109 │ └── limit hint: 1.00 110 └── -1 111 112 # -------------------------------------------------- 113 # EliminateOffset 114 # -------------------------------------------------- 115 norm expect=EliminateOffset 116 SELECT * FROM a OFFSET 0 117 ---- 118 scan a 119 ├── columns: k:1!null i:2 f:3 s:4 j:5 120 ├── key: (1) 121 └── fd: (1)-->(2-5) 122 123 norm expect=EliminateOffset 124 SELECT * FROM a LIMIT 5 OFFSET 0 125 ---- 126 limit 127 ├── columns: k:1!null i:2 f:3 s:4 j:5 128 ├── cardinality: [0 - 5] 129 ├── key: (1) 130 ├── fd: (1)-->(2-5) 131 ├── scan a 132 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 133 │ ├── key: (1) 134 │ ├── fd: (1)-->(2-5) 135 │ └── limit hint: 5.00 136 └── 5 137 138 norm expect-not=EliminateOffset 139 SELECT * FROM a LIMIT 5 OFFSET 1 140 ---- 141 offset 142 ├── columns: k:1!null i:2 f:3 s:4 j:5 143 ├── cardinality: [0 - 5] 144 ├── key: (1) 145 ├── fd: (1)-->(2-5) 146 ├── limit 147 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 148 │ ├── cardinality: [0 - 6] 149 │ ├── key: (1) 150 │ ├── fd: (1)-->(2-5) 151 │ ├── scan a 152 │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 153 │ │ ├── key: (1) 154 │ │ ├── fd: (1)-->(2-5) 155 │ │ └── limit hint: 6.00 156 │ └── 6 157 └── 1 158 159 # -------------------------------------------------- 160 # PushLimitIntoProject 161 # -------------------------------------------------- 162 norm expect=PushLimitIntoProject 163 SELECT k, f*2.0 AS r FROM a LIMIT 5 164 ---- 165 project 166 ├── columns: k:1!null r:6 167 ├── cardinality: [0 - 5] 168 ├── key: (1) 169 ├── fd: (1)-->(6) 170 ├── limit 171 │ ├── columns: k:1!null f:3 172 │ ├── cardinality: [0 - 5] 173 │ ├── key: (1) 174 │ ├── fd: (1)-->(3) 175 │ ├── scan a 176 │ │ ├── columns: k:1!null f:3 177 │ │ ├── key: (1) 178 │ │ ├── fd: (1)-->(3) 179 │ │ └── limit hint: 5.00 180 │ └── 5 181 └── projections 182 └── f:3 * 2.0 [as=r:6, outer=(3)] 183 184 norm expect=PushLimitIntoProject 185 SELECT k, f*2.0 AS r FROM a ORDER BY k LIMIT 5 186 ---- 187 project 188 ├── columns: k:1!null r:6 189 ├── cardinality: [0 - 5] 190 ├── key: (1) 191 ├── fd: (1)-->(6) 192 ├── ordering: +1 193 ├── limit 194 │ ├── columns: k:1!null f:3 195 │ ├── internal-ordering: +1 196 │ ├── cardinality: [0 - 5] 197 │ ├── key: (1) 198 │ ├── fd: (1)-->(3) 199 │ ├── ordering: +1 200 │ ├── scan a 201 │ │ ├── columns: k:1!null f:3 202 │ │ ├── key: (1) 203 │ │ ├── fd: (1)-->(3) 204 │ │ ├── ordering: +1 205 │ │ └── limit hint: 5.00 206 │ └── 5 207 └── projections 208 └── f:3 * 2.0 [as=r:6, outer=(3)] 209 210 # Don't push the limit through project when the ordering is on a 211 # synthesized column. 212 norm expect-not=PushLimitIntoProject 213 SELECT k, f*2.0 AS r FROM a ORDER BY r LIMIT 5 214 ---- 215 limit 216 ├── columns: k:1!null r:6 217 ├── internal-ordering: +6 218 ├── cardinality: [0 - 5] 219 ├── key: (1) 220 ├── fd: (1)-->(6) 221 ├── ordering: +6 222 ├── sort 223 │ ├── columns: k:1!null r:6 224 │ ├── key: (1) 225 │ ├── fd: (1)-->(6) 226 │ ├── ordering: +6 227 │ ├── limit hint: 5.00 228 │ └── project 229 │ ├── columns: r:6 k:1!null 230 │ ├── key: (1) 231 │ ├── fd: (1)-->(6) 232 │ ├── scan a 233 │ │ ├── columns: k:1!null f:3 234 │ │ ├── key: (1) 235 │ │ └── fd: (1)-->(3) 236 │ └── projections 237 │ └── f:3 * 2.0 [as=r:6, outer=(3)] 238 └── 5 239 240 241 # Detect PushLimitIntoProject and FilterUnusedLimitCols dependency cycle. 242 norm 243 SELECT f, f+1.1 AS r FROM (SELECT f, i FROM a GROUP BY f, i) a ORDER BY f LIMIT 5 244 ---- 245 project 246 ├── columns: f:3 r:6 247 ├── cardinality: [0 - 5] 248 ├── ordering: +3 249 ├── limit 250 │ ├── columns: i:2 f:3 251 │ ├── internal-ordering: +3 252 │ ├── cardinality: [0 - 5] 253 │ ├── key: (2,3) 254 │ ├── ordering: +3 255 │ ├── distinct-on 256 │ │ ├── columns: i:2 f:3 257 │ │ ├── grouping columns: i:2 f:3 258 │ │ ├── key: (2,3) 259 │ │ ├── ordering: +3 260 │ │ ├── limit hint: 5.00 261 │ │ └── sort 262 │ │ ├── columns: i:2 f:3 263 │ │ ├── ordering: +3 264 │ │ ├── limit hint: 6.02 265 │ │ └── scan a 266 │ │ └── columns: i:2 f:3 267 │ └── 5 268 └── projections 269 └── f:3 + 1.1 [as=r:6, outer=(3)] 270 271 # Don't push negative limit into Scan. 272 norm 273 SELECT * FROM a LIMIT -1 274 ---- 275 limit 276 ├── columns: k:1!null i:2 f:3 s:4 j:5 277 ├── cardinality: [0 - 0] 278 ├── immutable, side-effects 279 ├── key: () 280 ├── fd: ()-->(1-5) 281 ├── scan a 282 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 283 │ ├── key: (1) 284 │ ├── fd: (1)-->(2-5) 285 │ └── limit hint: 1.00 286 └── -1 287 288 # -------------------------------------------------- 289 # PushOffsetIntoProject 290 # -------------------------------------------------- 291 norm expect=PushOffsetIntoProject 292 SELECT k, f*2.0 AS r FROM a OFFSET 5 293 ---- 294 project 295 ├── columns: k:1!null r:6 296 ├── key: (1) 297 ├── fd: (1)-->(6) 298 ├── offset 299 │ ├── columns: k:1!null f:3 300 │ ├── key: (1) 301 │ ├── fd: (1)-->(3) 302 │ ├── scan a 303 │ │ ├── columns: k:1!null f:3 304 │ │ ├── key: (1) 305 │ │ └── fd: (1)-->(3) 306 │ └── 5 307 └── projections 308 └── f:3 * 2.0 [as=r:6, outer=(3)] 309 310 norm expect=PushOffsetIntoProject 311 SELECT k, f*2.0 AS r FROM a ORDER BY k OFFSET 5 312 ---- 313 project 314 ├── columns: k:1!null r:6 315 ├── key: (1) 316 ├── fd: (1)-->(6) 317 ├── ordering: +1 318 ├── offset 319 │ ├── columns: k:1!null f:3 320 │ ├── internal-ordering: +1 321 │ ├── key: (1) 322 │ ├── fd: (1)-->(3) 323 │ ├── ordering: +1 324 │ ├── scan a 325 │ │ ├── columns: k:1!null f:3 326 │ │ ├── key: (1) 327 │ │ ├── fd: (1)-->(3) 328 │ │ └── ordering: +1 329 │ └── 5 330 └── projections 331 └── f:3 * 2.0 [as=r:6, outer=(3)] 332 333 # Don't push the offset through project when the ordering is on a 334 # synthesized column. 335 norm expect-not=PushOffsetIntoProject 336 SELECT k, f*2.0 AS r FROM a ORDER BY r OFFSET 5 337 ---- 338 offset 339 ├── columns: k:1!null r:6 340 ├── internal-ordering: +6 341 ├── key: (1) 342 ├── fd: (1)-->(6) 343 ├── ordering: +6 344 ├── sort 345 │ ├── columns: k:1!null r:6 346 │ ├── key: (1) 347 │ ├── fd: (1)-->(6) 348 │ ├── ordering: +6 349 │ └── project 350 │ ├── columns: r:6 k:1!null 351 │ ├── key: (1) 352 │ ├── fd: (1)-->(6) 353 │ ├── scan a 354 │ │ ├── columns: k:1!null f:3 355 │ │ ├── key: (1) 356 │ │ └── fd: (1)-->(3) 357 │ └── projections 358 │ └── f:3 * 2.0 [as=r:6, outer=(3)] 359 └── 5 360 361 # Detect PushOffsetIntoProject and FilterUnusedOffsetCols dependency cycle. 362 norm 363 SELECT f, f+1.1 AS r FROM (SELECT f, i FROM a GROUP BY f, i) a ORDER BY f OFFSET 5 364 ---- 365 project 366 ├── columns: f:3 r:6 367 ├── ordering: +3 368 ├── offset 369 │ ├── columns: i:2 f:3 370 │ ├── internal-ordering: +3 371 │ ├── key: (2,3) 372 │ ├── ordering: +3 373 │ ├── distinct-on 374 │ │ ├── columns: i:2 f:3 375 │ │ ├── grouping columns: i:2 f:3 376 │ │ ├── key: (2,3) 377 │ │ ├── ordering: +3 378 │ │ └── sort 379 │ │ ├── columns: i:2 f:3 380 │ │ ├── ordering: +3 381 │ │ └── scan a 382 │ │ └── columns: i:2 f:3 383 │ └── 5 384 └── projections 385 └── f:3 + 1.1 [as=r:6, outer=(3)] 386 387 # -------------------------------------------------- 388 # PushLimitIntoProject + PushOffsetIntoProject 389 # -------------------------------------------------- 390 norm expect=(PushLimitIntoProject,PushOffsetIntoProject) 391 SELECT k, f*2.0 AS r FROM a OFFSET 5 LIMIT 10 392 ---- 393 project 394 ├── columns: k:1!null r:6 395 ├── cardinality: [0 - 10] 396 ├── key: (1) 397 ├── fd: (1)-->(6) 398 ├── offset 399 │ ├── columns: k:1!null f:3 400 │ ├── cardinality: [0 - 10] 401 │ ├── key: (1) 402 │ ├── fd: (1)-->(3) 403 │ ├── limit 404 │ │ ├── columns: k:1!null f:3 405 │ │ ├── cardinality: [0 - 15] 406 │ │ ├── key: (1) 407 │ │ ├── fd: (1)-->(3) 408 │ │ ├── scan a 409 │ │ │ ├── columns: k:1!null f:3 410 │ │ │ ├── key: (1) 411 │ │ │ ├── fd: (1)-->(3) 412 │ │ │ └── limit hint: 15.00 413 │ │ └── 15 414 │ └── 5 415 └── projections 416 └── f:3 * 2.0 [as=r:6, outer=(3)] 417 418 norm expect=(PushLimitIntoProject,PushOffsetIntoProject) 419 SELECT f, f+1.1 AS r FROM (SELECT f, i FROM a GROUP BY f, i) a ORDER BY f OFFSET 5 LIMIT 10 420 ---- 421 project 422 ├── columns: f:3 r:6 423 ├── cardinality: [0 - 10] 424 ├── ordering: +3 425 ├── offset 426 │ ├── columns: i:2 f:3 427 │ ├── internal-ordering: +3 428 │ ├── cardinality: [0 - 10] 429 │ ├── key: (2,3) 430 │ ├── ordering: +3 431 │ ├── limit 432 │ │ ├── columns: i:2 f:3 433 │ │ ├── internal-ordering: +3 434 │ │ ├── cardinality: [0 - 15] 435 │ │ ├── key: (2,3) 436 │ │ ├── ordering: +3 437 │ │ ├── distinct-on 438 │ │ │ ├── columns: i:2 f:3 439 │ │ │ ├── grouping columns: i:2 f:3 440 │ │ │ ├── key: (2,3) 441 │ │ │ ├── ordering: +3 442 │ │ │ ├── limit hint: 15.00 443 │ │ │ └── sort 444 │ │ │ ├── columns: i:2 f:3 445 │ │ │ ├── ordering: +3 446 │ │ │ ├── limit hint: 18.16 447 │ │ │ └── scan a 448 │ │ │ └── columns: i:2 f:3 449 │ │ └── 15 450 │ └── 5 451 └── projections 452 └── f:3 + 1.1 [as=r:6, outer=(3)] 453 454 # -------------------------------------------------- 455 # PushLimitIntoOffset 456 # -------------------------------------------------- 457 458 norm expect=PushLimitIntoOffset 459 SELECT k, i FROM a LIMIT 10 OFFSET 10 460 ---- 461 offset 462 ├── columns: k:1!null i:2 463 ├── cardinality: [0 - 10] 464 ├── key: (1) 465 ├── fd: (1)-->(2) 466 ├── limit 467 │ ├── columns: k:1!null i:2 468 │ ├── cardinality: [0 - 20] 469 │ ├── key: (1) 470 │ ├── fd: (1)-->(2) 471 │ ├── scan a 472 │ │ ├── columns: k:1!null i:2 473 │ │ ├── key: (1) 474 │ │ ├── fd: (1)-->(2) 475 │ │ └── limit hint: 20.00 476 │ └── 20 477 └── 10 478 479 norm expect=(PushLimitIntoOffset) 480 SELECT k, i FROM a OFFSET 10 LIMIT 10 481 ---- 482 offset 483 ├── columns: k:1!null i:2 484 ├── cardinality: [0 - 10] 485 ├── key: (1) 486 ├── fd: (1)-->(2) 487 ├── limit 488 │ ├── columns: k:1!null i:2 489 │ ├── cardinality: [0 - 20] 490 │ ├── key: (1) 491 │ ├── fd: (1)-->(2) 492 │ ├── scan a 493 │ │ ├── columns: k:1!null i:2 494 │ │ ├── key: (1) 495 │ │ ├── fd: (1)-->(2) 496 │ │ └── limit hint: 20.00 497 │ └── 20 498 └── 10 499 500 # Limit can be pushed into the ordering if they have the same ordering. 501 norm expect=PushLimitIntoOffset 502 SELECT k, i FROM (SELECT k, i FROM a ORDER BY i OFFSET 20) ORDER BY i LIMIT 10 503 ---- 504 offset 505 ├── columns: k:1!null i:2 506 ├── internal-ordering: +2 507 ├── cardinality: [0 - 10] 508 ├── key: (1) 509 ├── fd: (1)-->(2) 510 ├── ordering: +2 511 ├── limit 512 │ ├── columns: k:1!null i:2 513 │ ├── internal-ordering: +2 514 │ ├── cardinality: [0 - 30] 515 │ ├── key: (1) 516 │ ├── fd: (1)-->(2) 517 │ ├── ordering: +2 518 │ ├── sort 519 │ │ ├── columns: k:1!null i:2 520 │ │ ├── key: (1) 521 │ │ ├── fd: (1)-->(2) 522 │ │ ├── ordering: +2 523 │ │ ├── limit hint: 30.00 524 │ │ └── scan a 525 │ │ ├── columns: k:1!null i:2 526 │ │ ├── key: (1) 527 │ │ └── fd: (1)-->(2) 528 │ └── 30 529 └── 20 530 531 norm expect-not=PushLimitIntoOffset 532 SELECT k, i FROM (SELECT k, i FROM a ORDER BY i OFFSET 20) ORDER BY i DESC LIMIT 10 533 ---- 534 limit 535 ├── columns: k:1!null i:2 536 ├── internal-ordering: -2 537 ├── cardinality: [0 - 10] 538 ├── key: (1) 539 ├── fd: (1)-->(2) 540 ├── ordering: -2 541 ├── sort 542 │ ├── columns: k:1!null i:2 543 │ ├── key: (1) 544 │ ├── fd: (1)-->(2) 545 │ ├── ordering: -2 546 │ ├── limit hint: 10.00 547 │ └── offset 548 │ ├── columns: k:1!null i:2 549 │ ├── internal-ordering: +2 550 │ ├── key: (1) 551 │ ├── fd: (1)-->(2) 552 │ ├── sort 553 │ │ ├── columns: k:1!null i:2 554 │ │ ├── key: (1) 555 │ │ ├── fd: (1)-->(2) 556 │ │ ├── ordering: +2 557 │ │ └── scan a 558 │ │ ├── columns: k:1!null i:2 559 │ │ ├── key: (1) 560 │ │ └── fd: (1)-->(2) 561 │ └── 20 562 └── 10 563 564 # Using MaxInt64. Do not apply rule when sum overflows. 565 norm expect-not=PushLimitIntoOffset 566 SELECT k, i FROM a LIMIT 9223372036854775807 OFFSET 9223372036854775807 567 ---- 568 limit 569 ├── columns: k:1!null i:2 570 ├── key: (1) 571 ├── fd: (1)-->(2) 572 ├── offset 573 │ ├── columns: k:1!null i:2 574 │ ├── key: (1) 575 │ ├── fd: (1)-->(2) 576 │ ├── limit hint: 9223372036854775808.00 577 │ ├── scan a 578 │ │ ├── columns: k:1!null i:2 579 │ │ ├── key: (1) 580 │ │ ├── fd: (1)-->(2) 581 │ │ └── limit hint: 18446744073709551616.00 582 │ └── 9223372036854775807 583 └── 9223372036854775807 584 585 norm expect=PushLimitIntoOrdinality 586 SELECT * FROM (SELECT * FROM a ORDER BY k) WITH ORDINALITY LIMIT 10 587 ---- 588 ordinality 589 ├── columns: k:1!null i:2 f:3 s:4 j:5 ordinality:6!null 590 ├── cardinality: [0 - 10] 591 ├── key: (1) 592 ├── fd: (1)-->(2-6), (6)-->(1-5) 593 └── limit 594 ├── columns: k:1!null i:2 f:3 s:4 j:5 595 ├── internal-ordering: +1 596 ├── cardinality: [0 - 10] 597 ├── key: (1) 598 ├── fd: (1)-->(2-5) 599 ├── ordering: +1 600 ├── scan a 601 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 602 │ ├── key: (1) 603 │ ├── fd: (1)-->(2-5) 604 │ ├── ordering: +1 605 │ └── limit hint: 10.00 606 └── 10 607 608 norm expect=PushLimitIntoOrdinality 609 SELECT * FROM a WITH ORDINALITY ORDER BY k LIMIT 10 610 ---- 611 sort 612 ├── columns: k:1!null i:2 f:3 s:4 j:5 ordinality:6!null 613 ├── cardinality: [0 - 10] 614 ├── key: (1) 615 ├── fd: (1)-->(2-6), (6)-->(1-5) 616 ├── ordering: +1 617 └── ordinality 618 ├── columns: k:1!null i:2 f:3 s:4 j:5 ordinality:6!null 619 ├── cardinality: [0 - 10] 620 ├── key: (1) 621 ├── fd: (1)-->(2-6), (6)-->(1-5) 622 └── limit 623 ├── columns: k:1!null i:2 f:3 s:4 j:5 624 ├── internal-ordering: +1 625 ├── cardinality: [0 - 10] 626 ├── key: (1) 627 ├── fd: (1)-->(2-5) 628 ├── scan a 629 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 630 │ ├── key: (1) 631 │ ├── fd: (1)-->(2-5) 632 │ ├── ordering: +1 633 │ └── limit hint: 10.00 634 └── 10 635 636 637 # More complex example of an intersection: 638 # +(i|f) +s and +f have the intersection +(i|f) +s 639 norm expect=PushLimitIntoOrdinality 640 SELECT * FROM (SELECT * FROM a WHERE i=f ORDER BY i, s) WITH ORDINALITY ORDER BY f LIMIT 10 641 ---- 642 ordinality 643 ├── columns: k:1!null i:2!null f:3!null s:4 j:5 ordinality:6!null 644 ├── cardinality: [0 - 10] 645 ├── key: (1) 646 ├── fd: (1)-->(2-6), (2)==(3), (3)==(2), (6)-->(1-5) 647 ├── ordering: +(2|3) [actual: +2] 648 └── limit 649 ├── columns: k:1!null i:2!null f:3!null s:4 j:5 650 ├── internal-ordering: +(2|3),+4 651 ├── cardinality: [0 - 10] 652 ├── key: (1) 653 ├── fd: (1)-->(2-5), (2)==(3), (3)==(2) 654 ├── ordering: +(2|3),+4 [actual: +2,+4] 655 ├── sort 656 │ ├── columns: k:1!null i:2!null f:3!null s:4 j:5 657 │ ├── key: (1) 658 │ ├── fd: (1)-->(2-5), (2)==(3), (3)==(2) 659 │ ├── ordering: +(2|3),+4 [actual: +2,+4] 660 │ ├── limit hint: 10.00 661 │ └── select 662 │ ├── columns: k:1!null i:2!null f:3!null s:4 j:5 663 │ ├── key: (1) 664 │ ├── fd: (1)-->(2-5), (2)==(3), (3)==(2) 665 │ ├── scan a 666 │ │ ├── columns: k:1!null i:2 f:3 s:4 j:5 667 │ │ ├── key: (1) 668 │ │ └── fd: (1)-->(2-5) 669 │ └── filters 670 │ └── i:2 = f:3 [outer=(2,3), constraints=(/2: (/NULL - ]; /3: (/NULL - ]), fd=(2)==(3), (3)==(2)] 671 └── 10 672 673 norm expect-not=PushLimitIntoOrdinality 674 SELECT * FROM (SELECT * FROM a ORDER BY k) WITH ORDINALITY ORDER BY i LIMIT 10 675 ---- 676 limit 677 ├── columns: k:1!null i:2 f:3 s:4 j:5 ordinality:6!null 678 ├── internal-ordering: +2 679 ├── cardinality: [0 - 10] 680 ├── key: (1) 681 ├── fd: (1)-->(2-6), (6)-->(1-5) 682 ├── ordering: +2 683 ├── sort 684 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 ordinality:6!null 685 │ ├── key: (1) 686 │ ├── fd: (1)-->(2-6), (6)-->(1-5) 687 │ ├── ordering: +2 688 │ ├── limit hint: 10.00 689 │ └── ordinality 690 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 ordinality:6!null 691 │ ├── key: (1) 692 │ ├── fd: (1)-->(2-6), (6)-->(1-5) 693 │ └── scan a 694 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 695 │ ├── key: (1) 696 │ ├── fd: (1)-->(2-5) 697 │ └── ordering: +1 698 └── 10 699 700 norm expect-not=PushLimitIntoOrdinality 701 SELECT * FROM (SELECT * FROM a WITH ORDINALITY) ORDER BY ordinality LIMIT 10 702 ---- 703 limit 704 ├── columns: k:1!null i:2 f:3 s:4 j:5 ordinality:6!null 705 ├── internal-ordering: +6 706 ├── cardinality: [0 - 10] 707 ├── key: (1) 708 ├── fd: (1)-->(2-6), (6)-->(1-5) 709 ├── ordering: +6 710 ├── ordinality 711 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 ordinality:6!null 712 │ ├── key: (1) 713 │ ├── fd: (1)-->(2-6), (6)-->(1-5) 714 │ ├── ordering: +6 715 │ ├── limit hint: 10.00 716 │ └── scan a 717 │ ├── columns: k:1!null i:2 f:3 s:4 j:5 718 │ ├── key: (1) 719 │ ├── fd: (1)-->(2-5) 720 │ └── limit hint: 10.00 721 └── 10 722 723 # --------------------- 724 # PushLimitIntoLeftJoin 725 # --------------------- 726 727 norm expect=PushLimitIntoLeftJoin 728 SELECT * FROM ab LEFT JOIN uv ON a = u LIMIT 10 729 ---- 730 limit 731 ├── columns: a:1!null b:2 u:3 v:4 732 ├── cardinality: [0 - 10] 733 ├── key: (1) 734 ├── fd: (1)-->(2-4), (3)-->(4) 735 ├── left-join (hash) 736 │ ├── columns: a:1!null b:2 u:3 v:4 737 │ ├── key: (1) 738 │ ├── fd: (1)-->(2-4), (3)-->(4) 739 │ ├── limit hint: 10.00 740 │ ├── limit 741 │ │ ├── columns: a:1!null b:2 742 │ │ ├── cardinality: [0 - 10] 743 │ │ ├── key: (1) 744 │ │ ├── fd: (1)-->(2) 745 │ │ ├── scan ab 746 │ │ │ ├── columns: a:1!null b:2 747 │ │ │ ├── key: (1) 748 │ │ │ ├── fd: (1)-->(2) 749 │ │ │ └── limit hint: 10.00 750 │ │ └── 10 751 │ ├── scan uv 752 │ │ ├── columns: u:3!null v:4 753 │ │ ├── key: (3) 754 │ │ └── fd: (3)-->(4) 755 │ └── filters 756 │ └── a:1 = u:3 [outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)] 757 └── 10 758 759 # Ordering can be pushed down. 760 norm expect=PushLimitIntoLeftJoin 761 SELECT * FROM ab LEFT JOIN uv ON a = u ORDER BY a LIMIT 10 762 ---- 763 limit 764 ├── columns: a:1!null b:2 u:3 v:4 765 ├── internal-ordering: +1 766 ├── cardinality: [0 - 10] 767 ├── key: (1) 768 ├── fd: (1)-->(2-4), (3)-->(4) 769 ├── ordering: +1 770 ├── sort 771 │ ├── columns: a:1!null b:2 u:3 v:4 772 │ ├── key: (1) 773 │ ├── fd: (1)-->(2-4), (3)-->(4) 774 │ ├── ordering: +1 775 │ ├── limit hint: 10.00 776 │ └── left-join (hash) 777 │ ├── columns: a:1!null b:2 u:3 v:4 778 │ ├── key: (1) 779 │ ├── fd: (1)-->(2-4), (3)-->(4) 780 │ ├── limit 781 │ │ ├── columns: a:1!null b:2 782 │ │ ├── internal-ordering: +1 783 │ │ ├── cardinality: [0 - 10] 784 │ │ ├── key: (1) 785 │ │ ├── fd: (1)-->(2) 786 │ │ ├── scan ab 787 │ │ │ ├── columns: a:1!null b:2 788 │ │ │ ├── key: (1) 789 │ │ │ ├── fd: (1)-->(2) 790 │ │ │ ├── ordering: +1 791 │ │ │ └── limit hint: 10.00 792 │ │ └── 10 793 │ ├── scan uv 794 │ │ ├── columns: u:3!null v:4 795 │ │ ├── key: (3) 796 │ │ └── fd: (3)-->(4) 797 │ └── filters 798 │ └── a:1 = u:3 [outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)] 799 └── 10 800 801 norm expect=PushLimitIntoLeftJoin 802 SELECT * FROM ab LEFT JOIN uv ON a = u ORDER BY b LIMIT 10 803 ---- 804 limit 805 ├── columns: a:1!null b:2 u:3 v:4 806 ├── internal-ordering: +2 807 ├── cardinality: [0 - 10] 808 ├── key: (1) 809 ├── fd: (1)-->(2-4), (3)-->(4) 810 ├── ordering: +2 811 ├── sort 812 │ ├── columns: a:1!null b:2 u:3 v:4 813 │ ├── key: (1) 814 │ ├── fd: (1)-->(2-4), (3)-->(4) 815 │ ├── ordering: +2 816 │ ├── limit hint: 10.00 817 │ └── left-join (hash) 818 │ ├── columns: a:1!null b:2 u:3 v:4 819 │ ├── key: (1) 820 │ ├── fd: (1)-->(2-4), (3)-->(4) 821 │ ├── limit 822 │ │ ├── columns: a:1!null b:2 823 │ │ ├── internal-ordering: +2 824 │ │ ├── cardinality: [0 - 10] 825 │ │ ├── key: (1) 826 │ │ ├── fd: (1)-->(2) 827 │ │ ├── sort 828 │ │ │ ├── columns: a:1!null b:2 829 │ │ │ ├── key: (1) 830 │ │ │ ├── fd: (1)-->(2) 831 │ │ │ ├── ordering: +2 832 │ │ │ ├── limit hint: 10.00 833 │ │ │ └── scan ab 834 │ │ │ ├── columns: a:1!null b:2 835 │ │ │ ├── key: (1) 836 │ │ │ └── fd: (1)-->(2) 837 │ │ └── 10 838 │ ├── scan uv 839 │ │ ├── columns: u:3!null v:4 840 │ │ ├── key: (3) 841 │ │ └── fd: (3)-->(4) 842 │ └── filters 843 │ └── a:1 = u:3 [outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)] 844 └── 10 845 846 # Ordering on u is not equivalent to ordering on a because of NULLs; it cannot 847 # be pushed down. 848 norm expect-not=PushLimitIntoLeftJoin 849 SELECT * FROM ab LEFT JOIN uv ON a = u ORDER BY u LIMIT 10 850 ---- 851 limit 852 ├── columns: a:1!null b:2 u:3 v:4 853 ├── internal-ordering: +3 854 ├── cardinality: [0 - 10] 855 ├── key: (1) 856 ├── fd: (1)-->(2-4), (3)-->(4) 857 ├── ordering: +3 858 ├── sort 859 │ ├── columns: a:1!null b:2 u:3 v:4 860 │ ├── key: (1) 861 │ ├── fd: (1)-->(2-4), (3)-->(4) 862 │ ├── ordering: +3 863 │ ├── limit hint: 10.00 864 │ └── left-join (hash) 865 │ ├── columns: a:1!null b:2 u:3 v:4 866 │ ├── key: (1) 867 │ ├── fd: (1)-->(2-4), (3)-->(4) 868 │ ├── scan ab 869 │ │ ├── columns: a:1!null b:2 870 │ │ ├── key: (1) 871 │ │ └── fd: (1)-->(2) 872 │ ├── scan uv 873 │ │ ├── columns: u:3!null v:4 874 │ │ ├── key: (3) 875 │ │ └── fd: (3)-->(4) 876 │ └── filters 877 │ └── a:1 = u:3 [outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)] 878 └── 10 879 880 # Ordering cannot be pushed down. 881 norm expect-not=PushLimitIntoLeftJoin 882 SELECT * FROM ab LEFT JOIN uv ON a = u ORDER BY v LIMIT 10 883 ---- 884 limit 885 ├── columns: a:1!null b:2 u:3 v:4 886 ├── internal-ordering: +4 887 ├── cardinality: [0 - 10] 888 ├── key: (1) 889 ├── fd: (1)-->(2-4), (3)-->(4) 890 ├── ordering: +4 891 ├── sort 892 │ ├── columns: a:1!null b:2 u:3 v:4 893 │ ├── key: (1) 894 │ ├── fd: (1)-->(2-4), (3)-->(4) 895 │ ├── ordering: +4 896 │ ├── limit hint: 10.00 897 │ └── left-join (hash) 898 │ ├── columns: a:1!null b:2 u:3 v:4 899 │ ├── key: (1) 900 │ ├── fd: (1)-->(2-4), (3)-->(4) 901 │ ├── scan ab 902 │ │ ├── columns: a:1!null b:2 903 │ │ ├── key: (1) 904 │ │ └── fd: (1)-->(2) 905 │ ├── scan uv 906 │ │ ├── columns: u:3!null v:4 907 │ │ ├── key: (3) 908 │ │ └── fd: (3)-->(4) 909 │ └── filters 910 │ └── a:1 = u:3 [outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)] 911 └── 10 912 913 norm expect-not=PushLimitIntoLeftJoin 914 SELECT * FROM ab LEFT JOIN uv ON b = v ORDER BY a, v LIMIT 10 915 ---- 916 limit 917 ├── columns: a:1!null b:2 u:3 v:4 918 ├── internal-ordering: +1,+4 919 ├── cardinality: [0 - 10] 920 ├── key: (1,3) 921 ├── fd: (1)-->(2), (3)-->(4) 922 ├── ordering: +1,+4 923 ├── sort 924 │ ├── columns: a:1!null b:2 u:3 v:4 925 │ ├── key: (1,3) 926 │ ├── fd: (1)-->(2), (3)-->(4) 927 │ ├── ordering: +1,+4 928 │ ├── limit hint: 10.00 929 │ └── left-join (hash) 930 │ ├── columns: a:1!null b:2 u:3 v:4 931 │ ├── key: (1,3) 932 │ ├── fd: (1)-->(2), (3)-->(4) 933 │ ├── scan ab 934 │ │ ├── columns: a:1!null b:2 935 │ │ ├── key: (1) 936 │ │ └── fd: (1)-->(2) 937 │ ├── scan uv 938 │ │ ├── columns: u:3!null v:4 939 │ │ ├── key: (3) 940 │ │ └── fd: (3)-->(4) 941 │ └── filters 942 │ └── b:2 = v:4 [outer=(2,4), constraints=(/2: (/NULL - ]; /4: (/NULL - ]), fd=(2)==(4), (4)==(2)] 943 └── 10 944 945 norm expect-not=PushLimitIntoLeftJoin 946 SELECT * FROM ab LEFT JOIN uv ON a = u ORDER BY u, b LIMIT 10 947 ---- 948 limit 949 ├── columns: a:1!null b:2 u:3 v:4 950 ├── internal-ordering: +3,+2 951 ├── cardinality: [0 - 10] 952 ├── key: (1) 953 ├── fd: (1)-->(2-4), (3)-->(4) 954 ├── ordering: +3,+2 955 ├── sort 956 │ ├── columns: a:1!null b:2 u:3 v:4 957 │ ├── key: (1) 958 │ ├── fd: (1)-->(2-4), (3)-->(4) 959 │ ├── ordering: +3,+2 960 │ ├── limit hint: 10.00 961 │ └── left-join (hash) 962 │ ├── columns: a:1!null b:2 u:3 v:4 963 │ ├── key: (1) 964 │ ├── fd: (1)-->(2-4), (3)-->(4) 965 │ ├── scan ab 966 │ │ ├── columns: a:1!null b:2 967 │ │ ├── key: (1) 968 │ │ └── fd: (1)-->(2) 969 │ ├── scan uv 970 │ │ ├── columns: u:3!null v:4 971 │ │ ├── key: (3) 972 │ │ └── fd: (3)-->(4) 973 │ └── filters 974 │ └── a:1 = u:3 [outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)] 975 └── 10 976 977 # Rule should not fire if the input's cardinality is already less than the 978 # limit. 979 norm expect-not=PushLimitIntoLeftJoin 980 SELECT * FROM (SELECT * FROM ab LIMIT 5) LEFT JOIN uv ON a = u LIMIT 10 981 ---- 982 limit 983 ├── columns: a:1!null b:2 u:3 v:4 984 ├── cardinality: [0 - 10] 985 ├── key: (1) 986 ├── fd: (1)-->(2-4), (3)-->(4) 987 ├── left-join (hash) 988 │ ├── columns: a:1!null b:2 u:3 v:4 989 │ ├── key: (1) 990 │ ├── fd: (1)-->(2-4), (3)-->(4) 991 │ ├── limit hint: 10.00 992 │ ├── limit 993 │ │ ├── columns: a:1!null b:2 994 │ │ ├── cardinality: [0 - 5] 995 │ │ ├── key: (1) 996 │ │ ├── fd: (1)-->(2) 997 │ │ ├── scan ab 998 │ │ │ ├── columns: a:1!null b:2 999 │ │ │ ├── key: (1) 1000 │ │ │ ├── fd: (1)-->(2) 1001 │ │ │ └── limit hint: 5.00 1002 │ │ └── 5 1003 │ ├── scan uv 1004 │ │ ├── columns: u:3!null v:4 1005 │ │ ├── key: (3) 1006 │ │ └── fd: (3)-->(4) 1007 │ └── filters 1008 │ └── a:1 = u:3 [outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)] 1009 └── 10 1010 1011 # Push the limit even if the input is already limited (but with a higher limit). 1012 norm expect=PushLimitIntoLeftJoin 1013 SELECT * FROM (SELECT * FROM ab LIMIT 20) LEFT JOIN uv ON a = u LIMIT 10 1014 ---- 1015 limit 1016 ├── columns: a:1!null b:2 u:3 v:4 1017 ├── cardinality: [0 - 10] 1018 ├── key: (1) 1019 ├── fd: (1)-->(2-4), (3)-->(4) 1020 ├── left-join (hash) 1021 │ ├── columns: a:1!null b:2 u:3 v:4 1022 │ ├── key: (1) 1023 │ ├── fd: (1)-->(2-4), (3)-->(4) 1024 │ ├── limit hint: 10.00 1025 │ ├── limit 1026 │ │ ├── columns: a:1!null b:2 1027 │ │ ├── cardinality: [0 - 10] 1028 │ │ ├── key: (1) 1029 │ │ ├── fd: (1)-->(2) 1030 │ │ ├── limit 1031 │ │ │ ├── columns: a:1!null b:2 1032 │ │ │ ├── cardinality: [0 - 20] 1033 │ │ │ ├── key: (1) 1034 │ │ │ ├── fd: (1)-->(2) 1035 │ │ │ ├── limit hint: 10.00 1036 │ │ │ ├── scan ab 1037 │ │ │ │ ├── columns: a:1!null b:2 1038 │ │ │ │ ├── key: (1) 1039 │ │ │ │ ├── fd: (1)-->(2) 1040 │ │ │ │ └── limit hint: 20.00 1041 │ │ │ └── 20 1042 │ │ └── 10 1043 │ ├── scan uv 1044 │ │ ├── columns: u:3!null v:4 1045 │ │ ├── key: (3) 1046 │ │ └── fd: (3)-->(4) 1047 │ └── filters 1048 │ └── a:1 = u:3 [outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)] 1049 └── 10 1050 1051 # Don't push negative limits (or we would enter an infinite loop). 1052 norm expect-not=PushLimitIntoLeftJoin 1053 SELECT * FROM ab LEFT JOIN uv ON a = u LIMIT -1 1054 ---- 1055 limit 1056 ├── columns: a:1!null b:2 u:3 v:4 1057 ├── cardinality: [0 - 0] 1058 ├── immutable, side-effects 1059 ├── key: () 1060 ├── fd: ()-->(1-4) 1061 ├── left-join (hash) 1062 │ ├── columns: a:1!null b:2 u:3 v:4 1063 │ ├── key: (1) 1064 │ ├── fd: (1)-->(2-4), (3)-->(4) 1065 │ ├── limit hint: 1.00 1066 │ ├── scan ab 1067 │ │ ├── columns: a:1!null b:2 1068 │ │ ├── key: (1) 1069 │ │ └── fd: (1)-->(2) 1070 │ ├── scan uv 1071 │ │ ├── columns: u:3!null v:4 1072 │ │ ├── key: (3) 1073 │ │ └── fd: (3)-->(4) 1074 │ └── filters 1075 │ └── a:1 = u:3 [outer=(1,3), constraints=(/1: (/NULL - ]; /3: (/NULL - ]), fd=(1)==(3), (3)==(1)] 1076 └── -1