1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>The SQLite Query Optimizer Overview</title>
<style type="text/css">
body {
margin: auto;
font-family: Verdana, sans-serif;
padding: 8px 1%;
}
a { color: #044a64 }
a:visited { color: #734559 }
.logo { position:absolute; margin:3px; }
.tagline {
float:right;
text-align:right;
font-style:italic;
width:300px;
margin:12px;
margin-top:58px;
}
.menubar {
clear: both;
border-radius: 8px;
background: #044a64;
padding: 0px;
margin: 0px;
cell-spacing: 0px;
}
.toolbar {
text-align: center;
line-height: 1.6em;
margin: 0;
padding: 0px 8px;
}
.toolbar a { color: white; text-decoration: none; padding: 6px 12px; }
.toolbar a:visited { color: white; }
.toolbar a:hover { color: #044a64; background: white; }
.content { margin: 5%; }
.content dt { font-weight:bold; }
.content dd { margin-bottom: 25px; margin-left:20%; }
.content ul { padding:0px; padding-left: 15px; margin:0px; }
/* Things for "fancyformat" documents start here. */
.fancy img+p {font-style:italic}
.fancy .codeblock i { color: darkblue; }
.fancy h1,.fancy h2,.fancy h3,.fancy h4 {font-weight:normal;color:#044a64}
.fancy h2 { margin-left: 10px }
.fancy h3 { margin-left: 20px }
.fancy h4 { margin-left: 30px }
.fancy th {white-space:nowrap;text-align:left;border-bottom:solid 1px #444}
.fancy th, .fancy td {padding: 0.2em 1ex; vertical-align:top}
.fancy #toc a { color: darkblue ; text-decoration: none }
.fancy .todo { color: #AA3333 ; font-style : italic }
.fancy .todo:before { content: 'TODO:' }
.fancy p.todo { border: solid #AA3333 1px; padding: 1ex }
.fancy img { display:block; }
.fancy :link:hover, .fancy :visited:hover { background: wheat }
.fancy p,.fancy ul,.fancy ol { margin: 1em 5ex }
.fancy li p { margin: 1em 0 }
/* End of "fancyformat" specific rules. */
</style>
</head>
<body>
<div><!-- container div to satisfy validator -->
<a href="index.html">
<img class="logo" src="images/sqlite370_banner.gif" alt="SQLite Logo"
border="0"></a>
<div><!-- IE hack to prevent disappearing logo--></div>
<div class="tagline">Small. Fast. Reliable.<br>Choose any three.</div>
<table width=100% class="menubar"><tr>
<td width=100%>
<div class="toolbar">
<a href="about.html">About</a>
<a href="sitemap.html">Sitemap</a>
<a href="docs.html">Documentation</a>
<a href="download.html">Download</a>
<a href="copyright.html">License</a>
<a href="news.html">News</a>
<a href="support.html">Support</a>
</div>
<script>
gMsg = "Search SQLite Docs..."
function entersearch() {
var q = document.getElementById("q");
if( q.value == gMsg ) { q.value = "" }
q.style.color = "black"
q.style.fontStyle = "normal"
}
function leavesearch() {
var q = document.getElementById("q");
if( q.value == "" ) {
q.value = gMsg
q.style.color = "#044a64"
q.style.fontStyle = "italic"
}
}
function hideorshow(btn,obj){
var x = document.getElementById(obj);
var b = document.getElementById(btn);
if( x.style.display!='none' ){
x.style.display = 'none';
b.innerHTML='show';
}else{
x.style.display = '';
b.innerHTML='hide';
}
return false;
}
</script>
<td>
<div style="padding:0 1em 0px 0;white-space:nowrap">
<form name=f method="GET" action="http://www.sqlite.org/search">
<input id=q name=q type=text
onfocus="entersearch()" onblur="leavesearch()" style="width:24ex;padding:1px 1ex; border:solid white 1px; font-size:0.9em ; font-style:italic;color:#044a64;" value="Search SQLite Docs...">
<input type=submit value="Go" style="border:solid white 1px;background-color:#044a64;color:white;font-size:0.9em;padding:0 1ex">
</form>
</div>
</table>
<div class=startsearch></div>
<h1 align='center'> The SQLite Query Planner</h1><p>
This document provides overview of how the query planner and optimizer
for SQLite works.
</p>
<p>
Given a single SQL statement, there might be dozens, hundreds, or even
thousands of ways to implement that statement, depending on the complexity
of the statement itself and of the underlying database schema. The
task of the query planner is to select an algorithm from among the many
choices that provides the answer with a minimum of disk I/O and CPU
overhead.
</p>
<p>
With release 3.8.0, the SQLite query planner was reimplemented as the
<a href="queryplanner-ng.html">Next Generation Query Planner</a> or "NGQP". All of the features, techniques,
and algorithms described in this document are applicable to both the
pre-3.8.0 legacy query planner and to the NGQP. For further information on
how the NGQP differs from the legacy query planner, see the
<a href="queryplanner-ng.html">detailed description of the NGQP</a>.
</p>
<a name="where_clause"></a>
<h2>1.0 WHERE clause analysis</h2><p>
The WHERE clause on a query is broken up into "terms" where each term
is separated from the others by an AND operator.
If the WHERE clause is composed of constraints separate by the OR
operator then the entire clause is considered to be a single "term"
to which the <a href="#or_opt">OR-clause optimization</a> is applied.
</p>
<p>
All terms of the WHERE clause are analyzed to see if they can be
satisfied using indices.
To be usable by an index a term must be of one of the following
forms:
</p>
<blockquote><pre><b>
</b><i>column</i><b> = </b><i>expression</i><b>
</b><i>column</i><b> > </b><i>expression</i><b>
</b><i>column</i><b> >= </b><i>expression</i><b>
</b><i>column</i><b> < </b><i>expression</i><b>
</b><i>column</i><b> <= </b><i>expression</i><b>
</b><i>expression</i><b> = </b><i>column</i><b>
</b><i>expression</i><b> > </b><i>column</i><b>
</b><i>expression</i><b> >= </b><i>column</i><b>
</b><i>expression</i><b> < </b><i>column</i><b>
</b><i>expression</i><b> <= </b><i>column</i><b>
</b><i>column</i><b> IN (</b><i>expression-list</i><b>)
</b><i>column</i><b> IN (</b><i>subquery</i><b>)
</b><i>column</i><b> IS NULL
</b></pre></blockquote><p>
If an index is created using a statement like this:
</p>
<blockquote><pre>
CREATE INDEX idx_ex1 ON ex1(a,b,c,d,e,...,y,z);
</pre></blockquote><p>
Then the index might be used if the initial columns of the index
(columns a, b, and so forth) appear in WHERE clause terms.
The initial columns of the index must be used with
the <tt><b><big>=</big></b></tt> or <tt><b><big>IN</big></b></tt> or <tt><b><big>IS NULL</big></b></tt> operators.
The right-most column that is used can employ inequalities.
For the right-most
column of an index that is used, there can be up to two inequalities
that must sandwich the allowed values of the column between two extremes.
</p>
<p>
It is not necessary for every column of an index to appear in a
WHERE clause term in order for that index to be used.
But there can not be gaps in the columns of the index that are used.
Thus for the example index above, if there is no WHERE clause term
that constraints column c, then terms that constrain columns a and b can
be used with the index but not terms that constraint columns d through z.
Similarly, index columns will not normally be used (for indexing purposes)
if they are to the right of a
column that is constrained only by inequalities.
(See the <a href="optoverview.html#skipscan">skip-scan optimization</a> below for the exception.)
</p>
<a name="idxexamp"></a>
<h3>1.1 Index term usage examples</h3><p>
For the index above and WHERE clause like this:
</p>
<blockquote><pre>
... WHERE a=5 AND b IN (1,2,3) AND c IS NULL AND d='hello'
</pre></blockquote><p>
The first four columns a, b, c, and d of the index would be usable since
those four columns form a prefix of the index and are all bound by
equality constraints.
</p>
<p>
For the index above and WHERE clause like this:
</p>
<blockquote><pre>
... WHERE a=5 AND b IN (1,2,3) AND c>12 AND d='hello'
</pre></blockquote><p>
Only columns a, b, and c of the index would be usable. The d column
would not be usable because it occurs to the right of c and c is
constrained only by inequalities.
</p>
<p>
For the index above and WHERE clause like this:
</p>
<blockquote><pre>
... WHERE a=5 AND b IN (1,2,3) AND d='hello'
</pre></blockquote><p>
Only columns a and b of the index would be usable. The d column
would not be usable because column c is not constrained and there can
be no gaps in the set of columns that usable by the index.
</p>
<p>
For the index above and WHERE clause like this:
</p>
<blockquote><pre>
... WHERE b IN (1,2,3) AND c NOT NULL AND d='hello'
</pre></blockquote><p>
The index is not usable at all because the left-most column of the
index (column "a") is not constrained. Assuming there are no other
indices, the query above would result in a full table scan.
</p>
<p>
For the index above and WHERE clause like this:
</p>
<blockquote><pre>
... WHERE a=5 OR b IN (1,2,3) OR c NOT NULL OR d='hello'
</pre></blockquote><p>
The index is not usable because the WHERE clause terms are connected
by OR instead of AND. This query would result in a full table scan.
However, if three additional indices where added that contained columns
b, c, and d as their left-most columns, then the
<a href="#or_opt">OR-clause optimization</a> might apply.
</p>
<a name="between_opt"></a>
<h2>2.0 The BETWEEN optimization</h2><p>
If a term of the WHERE clause is of the following form:
</p>
<blockquote><pre><b>
</b><i>expr1</i><b> BETWEEN </b><i>expr2</i><b> AND </b><i>expr3</i><b>
</b></pre></blockquote><p>
Then two "virtual" terms are added as follows:
</p>
<blockquote><pre><b>
</b><i>expr1</i><b> >= </b><i>expr2</i><b> AND </b><i>expr1</i><b> <= </b><i>expr3</i><b>
</b></pre></blockquote><p>
Virtual terms are used for analysis only and do not cause any VDBE
code to be generated.
If both virtual terms end up being used as constraints on an index,
then the original BETWEEN term is omitted and the corresponding test
is not performed on input rows.
Thus if the BETWEEN term ends up being used as an index constraint
no tests are ever performed on that term.
On the other hand, the
virtual terms themselves never causes tests to be performed on
input rows.
Thus if the BETWEEN term is not used as an index constraint and
instead must be used to test input rows, the <i>expr1</i> expression is
only evaluated once.
</p>
<a name="or_opt"></a>
<h2>3.0 OR optimizations</h2><p>
WHERE clause constraints that are connected by OR instead of AND can
be handled in two different ways.
If a term consists of multiple subterms containing a common column
name and separated by OR, like this:
</p>
<blockquote><pre><b>
</b><i>column</i><b> = </b><i>expr1</i><b> OR </b><i>column</i><b> = </b><i>expr2</i><b> OR </b><i>column</i><b> = </b><i>expr3</i><b> OR ...
</b></pre></blockquote><p>
Then that term is rewritten as follows:
</p>
<blockquote><pre><b>
</b><i>column</i><b> IN (</b><i>expr1</i><b>,</b><i>expr2</i><b>,</b><i>expr3</i><b>,...)
</b></pre></blockquote><p>
The rewritten term then might go on to constrain an index using the
normal rules for <tt><b><big>IN</big></b></tt> operators. Note that <i>column</i> must be
the same column in every OR-connected subterm,
although the column can occur on either the left or the right side of
the <tt><b><big>=</big></b></tt> operator.
</p>
<p>
If and only if the previously described conversion of OR to an IN operator
does not work, the second OR-clause optimization is attempted.
Suppose the OR clause consists of multiple subterms as follows:
</p>
<blockquote><pre><b>
</b><i>expr1</i><b> OR </b><i>expr2</i><b> OR </b><i>expr3</i><b>
</b></pre></blockquote><p>
Individual subterms might be a single comparison expression like
<tt><b><big>a=5</big></b></tt> or <tt><b><big>x>y</big></b></tt> or they can be LIKE or BETWEEN expressions, or a subterm
can be a parenthesized list of AND-connected sub-subterms.
Each subterm is analyzed as if it were itself the entire WHERE clause
in order to see if the subterm is indexable by itself.
If <u>every</u> subterm of an OR clause is separately indexable
then the OR clause might be coded such that a separate index is used
to evaluate each term of the OR clause. One way to think about how
SQLite uses separate indices for each OR clause term is to imagine
that the WHERE clause where rewritten as follows:
</p>
<blockquote><pre><b>
rowid IN (SELECT rowid FROM </b><i>table</i><b> WHERE </b><i>expr1</i><b>
UNION SELECT rowid FROM </b><i>table</i><b> WHERE </b><i>expr2</i><b>
UNION SELECT rowid FROM </b><i>table</i><b> WHERE </b><i>expr3</i><b>)
</b></pre></blockquote><p>
The rewritten expression above is conceptual; WHERE clauses containing
OR are not really rewritten this way.
The actual implementation of the OR clause uses a mechanism that is
more efficient than subqueries and which works even
for tables where the "rowid" column name has been
overloaded for other uses and no longer refers to the real rowid.
But the essence of the implementation is captured by the statement
above: Separate indices are used to find candidate result rows
from each OR clause term and the final result is the union of
those rows.
</p>
<p>
Note that in most cases, SQLite will only use a single index for each
table in the FROM clause of a query. The second OR-clause optimization
described here is the exception to that rule. With an OR-clause,
a different index might be used for each subterm in the OR-clause.
</p>
<p>
For any given query, the fact that the OR-clause optimization described
here can be used does not guarantee that it will be used.
SQLite uses a cost-based query planner that estimates the CPU and
disk I/O costs of various competing query plans and chooses the plan
that it thinks will be the fastest. If there are many OR terms in
the WHERE clause or if some of the indices on individual OR-clause
subterms are not very selective, then SQLite might decide that it is
faster to use a different query algorithm, or even a full-table scan.
Application developers can use the
<a href="lang_explain.html">EXPLAIN QUERY PLAN</a> prefix on a statement to get a
high-level overview of the chosen query strategy.
</p>
<a name="like_opt"></a>
<h2>4.0 The LIKE optimization</h2><p>
Terms that are composed of the <a href="lang_expr.html#like">LIKE</a> or <a href="lang_expr.html#glob">GLOB</a> operator
can sometimes be used to constrain indices.
There are many conditions on this use:
</p>
<p>
<ol>
<li>The left-hand side of the LIKE or GLOB operator must be the name
of an indexed column with <a href="datatype3.html#affinity">TEXT affinity</a>.</li>
<li>The right-hand side of the LIKE or GLOB must be either a string literal
or a <a href="lang_expr.html#varparam">parameter</a> bound to a string literal
that does not begin with a wildcard character.</li>
<li>The ESCAPE clause cannot appear on the LIKE operator.</li>
<li>The built-in functions used to implement LIKE and GLOB must not
have been overloaded using the sqlite3_create_function() API.</li>
<li>For the GLOB operator, the column must be indexed using the
built-in BINARY collating sequence.</li>
<li>For the LIKE operator, if <a href="pragma.html#pragma_case_sensitive_like">case_sensitive_like</a> mode is enabled then
the column must indexed using BINARY collating sequence, or if
<a href="pragma.html#pragma_case_sensitive_like">case_sensitive_like</a> mode is disabled then the column must indexed
using built-in NOCASE collating sequence.</li>
</ol>
</p>
<p>
The LIKE operator has two modes that can be set by a
<a href="pragma.html#pragma_case_sensitive_like">pragma</a>. The
default mode is for LIKE comparisons to be insensitive to differences
of case for latin1 characters. Thus, by default, the following
expression is true:
</p>
<blockquote><pre>
'a' LIKE 'A'
</pre></blockquote><p>
But if the case_sensitive_like pragma is enabled as follows:
</p>
<blockquote><pre>
PRAGMA case_sensitive_like=ON;
</pre></blockquote><p>
Then the LIKE operator pays attention to case and the example above would
evaluate to false. Note that case insensitivity only applies to
latin1 characters - basically the upper and lower case letters of English
in the lower 127 byte codes of ASCII. International character sets
are case sensitive in SQLite unless an application-defined
<a href="datatype3.html#collation">collating sequence</a> and <a href="lang_corefunc.html#like">like() SQL function</a> are provided that
take non-ASCII characters into account.
But if an application-defined collating sequence and/or like() SQL
function are provided, the LIKE optimization described here will never
be taken.
</p>
<p>
The LIKE operator is case insensitive by default because this is what
the SQL standard requires. You can change the default behavior at
compile time by using the <a href="compile.html#case_sensitive_like">SQLITE_CASE_SENSITIVE_LIKE</a> command-line option
to the compiler.
</p>
<p>
The LIKE optimization might occur if the column named on the left of the
operator is indexed using the built-in BINARY collating sequence and
case_sensitive_like is turned on. Or the optimization might occur if
the column is indexed using the built-in NOCASE collating sequence and the
case_sensitive_like mode is off. These are the only two combinations
under which LIKE operators will be optimized.
</p>
<p>
The GLOB operator is always case sensitive. The column on the left side
of the GLOB operator must always use the built-in BINARY collating sequence
or no attempt will be made to optimize that operator with indices.
</p>
<p>
The LIKE optimization will only be attempted if
the right-hand side of the GLOB or LIKE operator is either
literal string or a <a href="lang_expr.html#varparam">parameter</a> that has been <a href="c3ref/bind_blob.html">bound</a>
to a string literal. The string literal must not
begin with a wildcard; if the right-hand side begins with a wildcard
character then this optimization is attempted. If the right-hand side
is a <a href="lang_expr.html#varparam">parameter</a> that is bound to a string, then this optimization is
only attempted if the <a href="c3ref/stmt.html">prepared statement</a> containing the expression
was compiled with <a href="c3ref/prepare.html">sqlite3_prepare_v2()</a> or <a href="c3ref/prepare.html">sqlite3_prepare16_v2()</a>.
The LIKE optimization is not attempted if the
right-hand side is a <a href="lang_expr.html#varparam">parameter</a> and the statement was prepared using
<a href="c3ref/prepare.html">sqlite3_prepare()</a> or <a href="c3ref/prepare.html">sqlite3_prepare16()</a>.
The LIKE optimization is not attempted if there is an EXCEPT phrase
on the LIKE operator.
</p>
<p>
Suppose the initial sequence of non-wildcard characters on the right-hand
side of the LIKE or GLOB operator is <i>x</i>. We are using a single
character to denote this non-wildcard prefix but the reader should
understand that the prefix can consist of more than 1 character.
Let <i>y</i> be the smallest string that is the same length as /x/ but which
compares greater than <i>x</i>. For example, if <i>x</i> is <tt><b><big>hello</big></b></tt> then
<i>y</i> would be <tt><b><big>hellp</big></b></tt>.
The LIKE and GLOB optimizations consist of adding two virtual terms
like this:
</p>
<blockquote><pre><b>
</b><i>column</i><b> >= </b><i>x</i><b> AND </b><i>column</i><b> < </b><i>y</i><b>
</b></pre></blockquote><p>
Under most circumstances, the original LIKE or GLOB operator is still
tested against each input row even if the virtual terms are used to
constrain an index. This is because we do not know what additional
constraints may be imposed by characters to the right
of the <i>x</i> prefix. However, if there is only a single
global wildcard to the right of <i>x</i>, then the original LIKE or
GLOB test is disabled.
In other words, if the pattern is like this:
</p>
<blockquote><pre><b>
</b><i>column</i><b> LIKE </b><i>x</i><b>%
</b><i>column</i><b> GLOB </b><i>x</i><b>*
</b></pre></blockquote><p>
then the original LIKE or GLOB tests are disabled when the virtual
terms constrain an index because in that case we know that all of the
rows selected by the index will pass the LIKE or GLOB test.
</p>
<p>
Note that when the right-hand side of a LIKE or GLOB operator is
a <a href="lang_expr.html#varparam">parameter</a> and the statement is prepared using <a href="c3ref/prepare.html">sqlite3_prepare_v2()</a>
or <a href="c3ref/prepare.html">sqlite3_prepare16_v2()</a> then the statement is automatically reparsed
and recompiled on the first <a href="c3ref/step.html">sqlite3_step()</a> call of each run if the binding
to the right-hand side parameter has changed since the previous run.
This reparse and recompile is essentially the same action that occurs
following a schema change. The recompile is necessary so that the query
planner can examine the new value bound to the right-hand side of the
LIKE or GLOB operator and determine whether or not to employ the
optimization described above.
</p>
<a name="skipscan"></a>
<h2>5.0 The Skip-Scan Optimization</h2><p>
The general rule is that indexes are only useful if there are
WHERE-clause constraints on the left-most columns of the index.
However, in some cases,
SQLite is able to use an index even if the first few columns of
the index are omitted from the WHERE clause but later columns
are included.
</p>
<p>
Consider a table such as the following:
</p>
<blockquote><pre>
CREATE TABLE people(
name TEXT PRIMARY KEY,
role TEXT NOT NULL,
height INT NOT NULL, -- in cm
CHECK( role IN ('student','teacher') )
);
CREATE INDEX people_idx1 ON people(role, height);
</pre></blockquote><p>
The people table has one entry for each person in a large
organization. Each person is either a "student" or a "teacher",
as determined by the "role" field. And we record the height in
centimeters of each person. The role and height are indexed.
Notice that the left-most column of the index is not very
selective - it only contains two possible values.
</p>
<p>
Now consider a query to find the names of everyone in the
organization that is 180cm tall or taller:
</p>
<blockquote><pre>
SELECT name FROM people WHERE height>=180;
</pre></blockquote><p>
Because the left-most column of the index does not appear in the
WHERE clause of the query, one is tempted to conclude that the
index is not usable here. But SQLite is able to use the index.
Conceptually, SQLite uses the index as if the query were more
like the following:
</p>
<blockquote><pre>
SELECT name FROM people
WHERE role IN (SELECT DISTINCT role FROM people)
AND height>=180;
</pre></blockquote><p>
Or this:
</p>
<blockquote><pre>
SELECT name FROM people WHERE role='teacher' AND height>=180
UNION ALL
SELECT name FROM people WHERE role='student' AND height>=180;
</pre></blockquote><p>
The alternative query formulations shown above are conceptual only.
SQLite does not really transform the query.
The actual query plan is like this:
SQLite locates the first possible value for "role", which it
can do by rewinding the "people_idx1" index to the beginning and reading
the first record. SQLite stores this first "role" value in an
internal variable that we will here call "$role". Then SQLite
runs a query like: "SELECT name FROM people WHERE role=$role AND height>=180".
This query has an equality constraint on the left-most column of the
index and so the index can be used to resolve that query. Once
that query is finished, SQLite then uses the "people_idx1" index to
locate the next value of the "role" column, using code that is logically
similar to "SELECT role FROM people WHERE role>$role LIMIT 1".
This new "role" value overwrites the $role variable, and the process
repeats until all possible values for "role" have been examined.
</p>
<p>
We call this kind of index usage a "skip-scan" because the database
engine is basically doing a full scan of the index but it optimizes the
scan (making it less than "full") by occasionally skipping ahead to the
next candidate value.
</p>
<p>
SQLite might use a skip-scan on an index if it knows that the first
one or more columns contain many duplication values.
If there are too few duplicates
in the left-most columns of the index, then it would
be faster to simply step ahead to the next value, and thus do
a full table scan, than to do a binary search on an index to locate
the next left-column value.
</p>
<p>
The only way that SQLite can know that the left-most columns of an index
have many duplicate is if the <a href="lang_analyze.html">ANALYZE</a> command has been run
on the database.
Without the results of ANALYZE, SQLite has to guess at the "shape" of
the data in the table, and the default guess is that there are an average
of 10 duplicates for every value in the left-most column of the index.
But skip-scan only becomes profitable (it only gets to be faster than
a full table scan) when the number of duplicates is about 18 or more.
Hence, a skip-scan is never used on a database that has not been analyzed.
</p>
<a name="joins"></a>
<h2>6.0 Joins</h2><p>
The ON and USING clauses of an inner join are converted into additional
terms of the WHERE clause prior to WHERE clause analysis described
above in paragraph 1.0. Thus with SQLite, there is no computational
advantage to use the newer SQL92 join syntax
over the older SQL89 comma-join syntax. They both end up accomplishing
exactly the same thing on inner joins.
</p>
<p>
For a LEFT OUTER JOIN the situation is more complex. The following
two queries are not equivalent:
</p>
<blockquote><pre>
SELECT * FROM tab1 LEFT JOIN tab2 ON tab1.x=tab2.y;
SELECT * FROM tab1 LEFT JOIN tab2 WHERE tab1.x=tab2.y;
</pre></blockquote><p>
For an inner join, the two queries above would be identical. But
special processing applies to the ON and USING clauses of an OUTER join:
specifically, the constraints in an ON or USING clause do not apply if
the right table of the join is on a null row, but the constraints do apply
in the WHERE clause. The net effect is that putting the ON or USING
clause expressions for a LEFT JOIN in the WHERE clause effectively converts
the query to an
ordinary INNER JOIN - albeit an inner join that runs more slowly.
</p>
<a name="table_order"></a>
<h3>6.1 Order of tables in a join</h3><p>
The current implementation of
SQLite uses only loop joins. That is to say, joins are implemented as
nested loops.
</p>
<p>
The default order of the nested loops in a join is for the left-most
table in the FROM clause to form the outer loop and the right-most
table to form the inner loop.
However, SQLite will nest the loops in a different order if doing so
will help it to select better indices.
</p>
<p>
Inner joins can be freely reordered. However a left outer join is
neither commutative nor associative and hence will not be reordered.
Inner joins to the left and right of the outer join might be reordered
if the optimizer thinks that is advantageous but the outer joins are
always evaluated in the order in which they occur.
</p>
<p>
SQLite <a href="lang_select.html#crossjoin">treats the CROSS JOIN operator specially</a>.
The CROSS JOIN operator is commutative in theory. But SQLite chooses to
never reorder tables in a CROSS JOIN. This provides a mechanism
by which the programmer can force SQLite to choose a particular loop nesting
order.
</p>
<p>
When selecting the order of tables in a join, SQLite uses an efficient
polynomial-time algorithm. Because of this,
SQLite is able to plan queries with 50- or 60-way joins in a matter of
microseconds.
</p>
<p>
Join reordering is automatic and usually works well enough that
programmers do not have to think about it, especially if <a href="lang_analyze.html">ANALYZE</a>
has been used to gather statistics about the available indices.
But occasionally some hints from the programmer are needed.
Consider, for example, the following schema:
</p>
<blockquote><pre>
CREATE TABLE node(
id INTEGER PRIMARY KEY,
name TEXT
);
CREATE INDEX node_idx ON node(name);
CREATE TABLE edge(
orig INTEGER REFERENCES node,
dest INTEGER REFERENCES node,
PRIMARY KEY(orig, dest)
);
CREATE INDEX edge_idx ON edge(dest,orig);
</pre></blockquote><p>
The schema above defines a directed graph with the ability to store a
name at each node. Now consider a query against this schema:
</p>
<blockquote><pre>
SELECT *
FROM edge AS e,
node AS n1,
node AS n2
WHERE n1.name = 'alice'
AND n2.name = 'bob'
AND e.orig = n1.id
AND e.dest = n2.id;
</pre></blockquote><p>
This query asks for is all information about edges that go from
nodes labeled "alice" to nodes labeled "bob".
The query optimizer in SQLite has basically two choices on how to
implement this query. (There are actually six different choices, but
we will only consider two of them here.)
Pseudocode below demonstrating these two choices.
</p>
<a name="option1"></a>
<p>Option 1:</p>
<blockquote><pre>
foreach n1 where n1.name='alice' do:
foreach n2 where n2.name='bob' do:
foreach e where e.orig=n1.id and e.dest=n2.id
return n1.*, n2.*, e.*
end
end
end
</pre></blockquote><a name="option2"></a>
<p>Option 2:</p>
<blockquote><pre>
foreach n1 where n1.name='alice' do:
foreach e where e.orig=n1.id do:
foreach n2 where n2.id=e.dest and n2.name='bob' do:
return n1.*, n2.*, e.*
end
end
end
</pre></blockquote><p>
The same indices are used to speed up every loop in both implementation
options.
The only difference in these two query plans is the order in which
the loops are nested.
</p>
<p>
So which query plan is better? It turns out that the answer depends on
what kind of data is found in the node and edge tables.
</p>
<p>
Let the number of alice nodes be M and the number of bob nodes be N.
Consider two scenarios. In the first scenario, M and N are both 2 but
there are thousands of edges on each node. In this case, option 1 is
preferred. With option 1, the inner loop checks for the existence of
an edge between a pair of nodes and outputs the result if found.
But because there are only 2 alice and bob nodes each, the inner loop
only has to run 4 times and the query is very quick. Option 2 would
take much longer here. The outer loop of option 2 only executes twice,
but because there are a large number of edges leaving each alice node,
the middle loop has to iterate many thousands of times. It will be
much slower. So in the first scenario, we prefer to use option 1.
</p>
<p>
Now consider the case where M and N are both 3500. Alice nodes are
abundant. But suppose each of these nodes is connected by only one
or two edges. In this case, option 2 is preferred. With option 2,
the outer loop still has to run 3500 times, but the middle loop only
runs once or twice for each outer loop and the inner loop will only
run once for each middle loop, if at all. So the total number of
iterations of the inner loop is around 7000. Option 1, on the other
hand, has to run both its outer loop and its middle loop 3500 times
each, resulting in 12 million iterations of the middle loop.
Thus in the second scenario, option 2 is nearly 2000 times faster
than option 1.
</p>
<p>
So you can see that depending on how the data is structured in the table,
either query plan 1 or query plan 2 might be better. Which plan does
SQLite choose by default? As of version 3.6.18, without running <a href="lang_analyze.html">ANALYZE</a>,
SQLite will choose option 2.
But if the <a href="lang_analyze.html">ANALYZE</a> command is run in order to gather statistics,
a different choice might be made if the statistics indicate that the
alternative is likely to run faster.
</p>
<a name="manctrl"></a>
<h3>6.2 Manual Control Of Query Plans Using SQLITE_STAT Tables</h3><p>
SQLite provides the ability for advanced programmers to exercise control
over the query plan chosen by the optimizer. One method for doing this
is to fudge the <a href="lang_analyze.html">ANALYZE</a> results in the <a href="fileformat2.html#stat1tab">sqlite_stat1</a>,
<a href="fileformat2.html#stat3tab">sqlite_stat3</a>, and/or <a href="fileformat2.html#stat4tab">sqlite_stat4</a> tables. That approach is not
recommended except for the one scenario described in the next paragraph.
</p>
<p>
For a program that uses an SQLite database as its
<a href="appfileformat.html">application file-format</a>,
when a new database instance is first created the <a href="lang_analyze.html">ANALYZE</a>
command is ineffective because the database contain no data from which
to gather statistics. In that case, one could construct a large prototype
database containing typical data during development and run the
<a href="lang_analyze.html">ANALYZE</a> command on this prototype database to gather statistics,
then save the prototype statistics as part of the application.
After deployment, when the application goes to create a new database file,
it can run the <a href="lang_analyze.html">ANALYZE</a> command in order to create the statistics
tables, then copy the precomputed statistics obtained
from the prototype database into these new statistics tables.
In that way, statistics from large working data sets can be preloaded
into newly created application files.
</p>
<a name="crossjoin"></a>
<h3>6.3 Manual Control Of Query Plans Using CROSS JOIN</h3><p>
Programmers can force SQLite to use a particular loop nesting order
for a join by using the CROSS JOIN operator instead of just JOIN,
INNER JOIN, NATURAL JOIN, or a "," join. Though CROSS JOINs are
commutative in theory, SQLite chooses to never reorder the tables in
a CROSS JOIN. Hence, the left table of a CROSS JOIN will always be
in an outer loop relative to the right table.
</p>
<p>
In the following query, the optimizer is free to reorder the
tables of FROM clause anyway it sees fit:
</p>
<blockquote><pre>
SELECT *
FROM node AS n1,
edge AS e,
node AS n2
WHERE n1.name = 'alice'
AND n2.name = 'bob'
AND e.orig = n1.id
AND e.dest = n2.id;
</pre></blockquote><p>
But in the following logically equivalent formulation of the same query,
the substitution of "CROSS JOIN" for the "," means that the order
of tables must be N1, E, N2.
</p>
<blockquote><pre>
SELECT *
FROM node AS n1 CROSS JOIN
edge AS e CROSS JOIN
node AS n2
WHERE n1.name = 'alice'
AND n2.name = 'bob'
AND e.orig = n1.id
AND e.dest = n2.id;
</pre></blockquote><p>
In the latter query, the query plan must be
<a href="#option2">option 2</a>. Note that
you must use the keyword "CROSS" in order to disable the table reordering
optimization; INNER JOIN, NATURAL JOIN, JOIN, and other similar
combinations work just like a comma join in that the optimizer is
free to reorder tables as it sees fit. (Table reordering is also
disabled on an outer join, but that is because outer joins are not
associative or commutative. Reordering tables in OUTER JOIN changes
the result.)
</p>
<p>
See "<a href="queryplanner-ng.html#fossilcasestudy">The Fossil NGQP Upgrade Case Study</a>" for another real-world example
of using CROSS JOIN to manually control the nesting order of a join.
The <a href="queryplanner-ng.html#howtofix">query planner checklist</a> found later in the same document provides
further guidance on manual control of the query planner.
</p>
<a name="multi_index"></a>
<h2>7.0 Choosing between multiple indices</h2><p>
Each table in the FROM clause of a query can use at most one index
(except when the <a href="#or_opt">OR-clause optimization</a> comes into
play)
and SQLite strives to use at least one index on each table. Sometimes,
two or more indices might be candidates for use on a single table.
For example:
</p>
<blockquote><pre>
CREATE TABLE ex2(x,y,z);
CREATE INDEX ex2i1 ON ex2(x);
CREATE INDEX ex2i2 ON ex2(y);
SELECT z FROM ex2 WHERE x=5 AND y=6;
</pre></blockquote><p>
For the SELECT statement above, the optimizer can use the ex2i1 index
to lookup rows of ex2 that contain x=5 and then test each row against
the y=6 term. Or it can use the ex2i2 index to lookup rows
of ex2 that contain y=6 then test each of those rows against the
x=5 term.
</p>
<p>
When faced with a choice of two or more indices, SQLite tries to estimate
the total amount of work needed to perform the query using each option.
It then selects the option that gives the least estimated work.
</p>
<p>
To help the optimizer get a more accurate estimate of the work involved
in using various indices, the user may optionally run the <a href="lang_analyze.html">ANALYZE</a> command.
The <a href="lang_analyze.html">ANALYZE</a> command scans all indices of database where there might
be a choice between two or more indices and gathers statistics on the
selectiveness of those indices. The statistics gathered by
this scan are stored in special database tables names shows names all
begin with "<b>sqlite_stat</b>".
The content of these tables is not updated as the database
changes so after making significant changes it might be prudent to
rerun <a href="lang_analyze.html">ANALYZE</a>.
The results of an ANALYZE command are only available to database connections
that are opened after the ANALYZE command completes.
</p>
<p>
The various <b>sqlite_stat</b><i>N</i> tables contain information on how
selective the various indices are. For example, the <a href="fileformat2.html#stat1tab">sqlite_stat1</a>
table might indicate that an equality constraint on column x reduces the
search space to 10 rows on average, whereas an equality constraint on
column y reduces the search space to 3 rows on average. In that case,
SQLite would prefer to use index ex2i2 since that index is more selective.
</p>
<a name="uplus"></a>
<h3>7.1 Disqualifying WHERE Clause Terms Using Unary-"+"</h3><p>
Terms of the WHERE clause can be manually disqualified for use with
indices by prepending a unary <tt><b><big>+</big></b></tt> operator to the column name. The
unary <tt><b><big>+</big></b></tt> is a no-op and will not generate any byte code in the prepared
statement.
But the unary <tt><b><big>+</big></b></tt> operator will prevent the term from constraining an index.
So, in the example above, if the query were rewritten as:
</p>
<blockquote><pre>
SELECT z FROM ex2 WHERE +x=5 AND y=6;
</pre></blockquote><p>
The <tt><b><big>+</big></b></tt> operator on the <tt><b><big>x</big></b></tt> column will prevent that term from
constraining an index. This would force the use of the ex2i2 index.
</p>
<p>
Note that the unary <tt><b><big>+</big></b></tt> operator also removes
<a href="datatype3.html#affinity">type affinity</a> from
an expression, and in some cases this can cause subtle changes in
the meaning of an expression.
In the example above,
if column <tt><b><big>x</big></b></tt> has <a href="datatype3.html#affinity">TEXT affinity</a>
then the comparison "x=5" will be done as text. But the <tt><b><big>+</big></b></tt> operator
removes the affinity. So the comparison "+x=5" will compare the text
in column <tt><b><big>x</big></b></tt> with the numeric value 5 and will always be false.
</p>
<a name="rangequery"></a>
<h3>7.2 Range Queries</h3><p>
Consider a slightly different scenario:
</p>
<blockquote><pre>
CREATE TABLE ex2(x,y,z);
CREATE INDEX ex2i1 ON ex2(x);
CREATE INDEX ex2i2 ON ex2(y);
SELECT z FROM ex2 WHERE x BETWEEN 1 AND 100 AND y BETWEEN 1 AND 100;
</pre></blockquote><p>
Further suppose that column x contains values spread out
between 0 and 1,000,000 and column y contains values
that span between 0 and 1,000. In that scenario,
the range constraint on column x should reduce the search space by
a factor of 10,000 whereas the range constraint on column y should
reduce the search space by a factor of only 10. So the ex2i1 index
should be preferred.
</p>
<p>
SQLite will make this determination, but only if it has been compiled
with <a href="compile.html#enable_stat3">SQLITE_ENABLE_STAT3</a> or <a href="compile.html#enable_stat4">SQLITE_ENABLE_STAT4</a>.
The <a href="compile.html#enable_stat3">SQLITE_ENABLE_STAT3</a> and <a href="compile.html#enable_stat4">SQLITE_ENABLE_STAT4</a> options causes
the <a href="lang_analyze.html">ANALYZE</a> command to collect a histogram of column content in the
<a href="fileformat2.html#stat3tab">sqlite_stat3</a> or <a href="fileformat2.html#stat4tab">sqlite_stat4</a> tables and to use this histogram to
make a better guess at the best query to use for range constraints
such as the above. The main difference between STAT3 and STAT4 is
that STAT3 records histogram data for only the left-most column of
an index whereas STAT4 records histogram data for all columns of an
index. For single-column indexes, STAT3 and STAT4 work the same.
</p>
<p>
The histogram data is only useful if the right-hand side of the constraint
is a simple compile-time constant or <a href="lang_expr.html#varparam">parameter</a> and not an expression.
</p>
<p>
Another limitation of the histogram data is that it only applies to the
left-most column on an index. Consider this scenario:
</p>
<blockquote><pre>
CREATE TABLE ex3(w,x,y,z);
CREATE INDEX ex3i1 ON ex2(w, x);
CREATE INDEX ex3i2 ON ex2(w, y);
SELECT z FROM ex3 WHERE w=5 AND x BETWEEN 1 AND 100 AND y BETWEEN 1 AND 100;
</pre></blockquote><p>
Here the inequalities are on columns x and y which are not the
left-most index columns. Hence, the histogram data which is collected no
left-most column of indices is useless in helping to choose between the
range constraints on columns x and y.
</p>
<h2>8.0 Covering Indices</h2><p>
When doing an indexed lookup of a row, the usual procedure is to
do a binary search on the index to find the index entry, then extract
the <a href="lang_createtable.html#rowid">rowid</a> from the index and use that <a href="lang_createtable.html#rowid">rowid</a> to do a binary search on
the original table. Thus a typical indexed lookup involves two
binary searches.
If, however, all columns that were to be fetched from the table are
already available in the index itself, SQLite will use the values
contained in the index and will never look up the original table
row. This saves one binary search for each row and can make many
queries run twice as fast.
</p>
<p>
When an index contains all of the data needed for a query and when the
original table never needs to be consulted, we call that index a
"covering index".
</p>
<a name="order_by"></a>
<h2>9.0 ORDER BY optimizations</h2><p>
SQLite attempts to use an index to satisfy the ORDER BY clause of a
query when possible.
When faced with the choice of using an index to satisfy WHERE clause
constraints or satisfying an ORDER BY clause, SQLite does the same
cost analysis described above
and chooses the index that it believes will result in the fastest answer.
</p>
<p>
SQLite will also attempt to use indices to help satisfy GROUP BY clauses
and the DISTINCT keyword. If the nested loops of the join can be arranged
such that rows that are equivalent for the GROUP BY or for the DISTINCT are
consecutive, then the GROUP BY or DISTINCT logic can determine if the
current row is part of the same group or if the current row is distinct
simply by comparing the current row to the previous row.
This can be much faster than the alternative of comparing each row to
all prior rows.
</p>
<a name="partsort"></a>
<h3>9.1 Partial ORDER BY Via Index</h3><p>
If a query contains an ORDER BY clause with multiple terms, it might
be that SQLite can use indices to cause rows to come out in the order
of some prefix of the terms in the ORDER BY but that later terms in
the ORDER BY are not satisfied. In that case, SQLite does block sorting.
Suppose the ORDER BY clause has four terms and the natural order of the
query results in rows appearing in order of the first two terms. As
each row is output by the query engine and enters the sorter, the
outputs in the current row corresponding to the first two terms of
the ORDER BY are compared against the previous row. If they have
changed, the current sort is finished and output and a new sort is
started. This results in a slightly faster sort. But the bigger
advantages are that many fewer rows need to be held in memory,
reducing memory requirements, and outputs can begin to appear before
the core query has run to completion.
</p>
<a name="flattening"></a>
<h2>10.0 Subquery flattening</h2><p>
When a subquery occurs in the FROM clause of a SELECT, the simplest
behavior is to evaluate the subquery into a transient table, then run
the outer SELECT against the transient table. But such a plan
can be suboptimal since the transient table will not have any indices
and the outer query (which is likely a join) will be forced to do a
full table scan on the transient table.
</p>
<p>
To overcome this problem, SQLite attempts to flatten subqueries in
the FROM clause of a SELECT.
This involves inserting the FROM clause of the subquery into the
FROM clause of the outer query and rewriting expressions in
the outer query that refer to the result set of the subquery.
For example:
</p>
<blockquote><pre>
SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5
</pre></blockquote><p>
Would be rewritten using query flattening as:
</p>
<blockquote><pre>
SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
</pre></blockquote><p>
There is a long list of conditions that must all be met in order for
query flattening to occur. Some of the constraints are marked as
obsolete by italic text. These extra constraints are retained in the
documentation to preserve the numbering of the other constraints.
</p>
<p>
<ol>
<li value="1"> The subquery and the outer query do not both use aggregates.
<li value="2">
The subquery is not an aggregate or the outer query is not a join.
<li value="3">
The subquery is not the right operand of a left outer join.
<li value="4"> The subquery is not DISTINCT.
<li value="5"> <i>(Subsumed into constraint 4)</i>
<li value="6">
The subquery does not use aggregates or the outer query is not
DISTINCT.
<li value="7">
The subquery has a FROM clause.
<li value="8">
The subquery does not use LIMIT or the outer query is not a join.
<li value="9">
The subquery does not use LIMIT or the outer query does not use
aggregates.
<li value="10">
The subquery does not use aggregates or the outer query does not
use LIMIT.
<li value="11">
The subquery and the outer query do not both have ORDER BY clauses.
<li value="12"> <i>(Subsumed into constraint 3)</i>
<li value="13"> The subquery and outer query do not both use LIMIT.
<li value="14"> The subquery does not use OFFSET.
<li value="15">
The outer query is not part of a compound select or the
subquery does not have a LIMIT clause.
<li value="16">
The outer query is not an aggregate or the subquery does
not contain ORDER BY.
<li value="17">
The sub-query is not a compound select, or it is a UNION ALL
compound clause made up entirely of non-aggregate queries, and
the parent query:
<ul>
<li> is not itself part of a compound select,
<li> is not an aggregate or DISTINCT query, and
<li> is not a join.
</ul>
The parent and sub-query may contain WHERE clauses. Subject to
rules (11), (12) and (13), they may also contain ORDER BY,
LIMIT and OFFSET clauses.
<li value="18">
If the sub-query is a compound select, then all terms of the
ORDER by clause of the parent must be simple references to
columns of the sub-query.
<li value="19">
The subquery does not use LIMIT or the outer query does not
have a WHERE clause.
<li value="20">
If the sub-query is a compound select, then it must not use
an ORDER BY clause.
<li value="21">
The subquery does not use LIMIT or the outer query is not
DISTINCT.
<li value="22"> The subquery is not a recursive CTE.
<li value="23"> The parent is not a recursive CTE, or the sub-query
is not a compound query.
</ol>
</p>
<p>
The casual reader is not expected to understand or remember any part of
the list above. The point of this list is to demonstrate
that the decision of whether or not to flatten a query is complex.
</p>
<p>
Query flattening is an important optimization when views are used as
each use of a view is translated into a subquery.
</p>
<a name="minmax"></a>
<h2>11.0 The MIN/MAX optimization</h2><p>
Queries that contain a single MIN() or MAX() aggregate function whose
argument is the left-most column of an index might be satisfied
by doing a single index lookup rather than by scanning the entire table.
Examples:
</p>
<blockquote><pre>
SELECT MIN(x) FROM table;
SELECT MAX(x)+1 FROM table;
</pre></blockquote><a name="autoindex"></a>
<h2>12.0 Automatic Indices</h2><p>
When no indices are available to aid the evaluation of a query, SQLite
might create an automatic index that lasts only for the duration
of a single SQL statement.
Since the cost of constructing the automatic index is
O(NlogN) (where N is the number of entries in the table) and the cost of
doing a full table scan is only O(N), an automatic index will
only be created if SQLite expects that the lookup will be run more than
logN times during the course of the SQL statement. Consider an example:
</p>
<blockquote><pre>
CREATE TABLE t1(a,b);
CREATE TABLE t2(c,d);
-- Insert many rows into both t1 and t2
SELECT * FROM t1, t2 WHERE a=c;
</pre></blockquote><p>
In the query above, if both t1 and t2 have approximately N rows, then
without any indices the query will require O(N*N) time. On the other
hand, creating an index on table t2 requires O(NlogN) time and then using
that index to evaluate the query requires an additional O(NlogN) time.
In the absence of <a href="lang_analyze.html">ANALYZE</a> information, SQLite guesses that N is one
million and hence it believes that constructing the automatic index will
be the cheaper approach.
</p>
<p>
An automatic index might also be used for a subquery:
</p>
<blockquote><pre>
CREATE TABLE t1(a,b);
CREATE TABLE t2(c,d);
-- Insert many rows into both t1 and t2
SELECT a, (SELECT d FROM t2 WHERE c=b) FROM t1;
</pre></blockquote><p>
In this example, the t2 table is used in a subquery to translate values
of the t1.b column. If each table contains N rows, SQLite expects that
the subquery will run N times, and hence it will believe it is faster
to construct an automatic, transient index on t2 first and then using
that index to satisfy the N instances of the subquery.
</p>
<p>
The automatic indexing capability can be disabled at run-time using
the <a href="pragma.html#pragma_automatic_index">automatic_index pragma</a>. Automatic indexing is turned on by
default, but this can be changed so that automatic indexing is off
by default using the <a href="compile.html#default_automatic_index">SQLITE_DEFAULT_AUTOMATIC_INDEX</a> compile-time option.
The ability to create automatic indices can be completely disabled by
compiling with the <a href="compile.html#omit_automatic_index">SQLITE_OMIT_AUTOMATIC_INDEX</a> compile-time option.
</p>
<p>
In SQLite version 3.8.0, an <a href="rescode.html#warning_autoindex">SQLITE_WARNING_AUTOINDEX</a> message is sent
to the <a href="errlog.html">error log</a> every time a statement is prepared that uses an
automatic index. Application developers can and should use these warnings
to identify the need for new persistent indices in the schema.
</p>
<p>
Future releases of SQLite may disable automatic indices by default.
</p>
|