Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Modify the vdbe code generated by ANALYZE to use fewer memory cells and cursor slots. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | sqlite_stat4 |
Files: | files | file ages | folders |
SHA1: |
4a51cf289fad8aebc637b5f96488de18 |
User & Date: | dan 2013-08-05 19:04:07.083 |
Context
2013-08-06
| ||
20:01 | When possible, use the multi-column samples in sqlite_stat4 to estimate the number of index rows scanned by a query plan. (check-in: 2973f5ca73 user: dan tags: sqlite_stat4) | |
2013-08-05
| ||
19:04 | Modify the vdbe code generated by ANALYZE to use fewer memory cells and cursor slots. (check-in: 4a51cf289f user: dan tags: sqlite_stat4) | |
18:00 | Use N separate cursors when scanning an index with N columns to collect sqlite_stat4 data. This fixes a problem with collecting incorrect nEq values from multi-column indexes. (check-in: 3a71afe674 user: dan tags: sqlite_stat4) | |
Changes
Changes to src/analyze.c.
︙ | ︙ | |||
501 502 503 504 505 506 507 | ** a single table. */ static void analyzeOneTable( Parse *pParse, /* Parser context */ Table *pTab, /* Table whose indices are to be analyzed */ Index *pOnlyIdx, /* If not NULL, only analyze this one index */ int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */ | | > > < < < < < < < < < > > > > | 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 | ** a single table. */ static void analyzeOneTable( Parse *pParse, /* Parser context */ Table *pTab, /* Table whose indices are to be analyzed */ Index *pOnlyIdx, /* If not NULL, only analyze this one index */ int iStatCur, /* Index of VdbeCursor that writes the sqlite_stat1 table */ int iMem, /* Available memory locations begin here */ int iTab /* Next available cursor */ ){ sqlite3 *db = pParse->db; /* Database handle */ Index *pIdx; /* An index to being analyzed */ int iIdxCur; /* Cursor open on index being analyzed */ int iTabCur; /* Table cursor */ Vdbe *v; /* The virtual machine being built up */ int i; /* Loop counter */ int jZeroRows = -1; /* Jump from here if number of rows is zero */ int iDb; /* Index of database containing pTab */ u8 needTableCnt = 1; /* True to count the table */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ int regStat1 = iMem++; /* The stat column of sqlite_stat1 */ #ifdef SQLITE_ENABLE_STAT4 int regNumEq = regStat1; /* Number of instances. Same as regStat1 */ int regNumLt = iMem++; /* Number of keys less than regSample */ int regNumDLt = iMem++; /* Number of distinct keys less than regSample */ int regSample = iMem++; /* The next sample value */ int regLoop = iMem++; /* Loop counter */ int shortJump = 0; /* Instruction address */ #endif int regCol = iMem++; /* Content of a column in analyzed table */ int regRec = iMem++; /* Register holding completed record */ int regTemp = iMem++; /* Temporary use register */ int regNewRowid = iMem++; /* Rowid for the inserted record */ int regEof = iMem++; /* True once cursors are all at EOF */ int regCnt = iMem++; /* Row counter */ int regStat4 = iMem++; /* Register to hold Stat4Accum object */ int regRowid = iMem++; /* Rowid argument passed to stat4_push() */ pParse->nMem = MAX(pParse->nMem, regRowid); v = sqlite3GetVdbe(pParse); if( v==0 || NEVER(pTab==0) ){ return; } if( pTab->tnum==0 ){ /* Do not gather statistics on views or virtual tables */ return; |
︙ | ︙ | |||
564 565 566 567 568 569 570 | return; } #endif /* Establish a read-lock on the table at the shared-cache level. ** Also open a read-only cursor on the table. */ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); | | > < < < < | 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 | return; } #endif /* Establish a read-lock on the table at the shared-cache level. ** Also open a read-only cursor on the table. */ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); iTabCur = iTab++; pParse->nTab = MAX(pParse->nTab, iTab); sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead); sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int nCol; /* Number of columns indexed by pIdx */ KeyInfo *pKey; /* KeyInfo structure for pIdx */ int *aChngAddr; /* Array of jump instruction addresses */ int regPrev; /* First in array of previous values */ int regDLte; /* First in array of nDlt registers */ int regLt; /* First in array of nLt registers */ int regEq; /* First in array of nEq registers */ int endOfScan; /* Label to jump to once scan is finished */ if( pOnlyIdx && pOnlyIdx!=pIdx ) continue; if( pIdx->pPartIdxWhere==0 ) needTableCnt = 0; VdbeNoopComment((v, "Begin analysis of %s", pIdx->zName)); nCol = pIdx->nColumn; aChngAddr = sqlite3DbMallocRaw(db, sizeof(int)*nCol); |
︙ | ︙ | |||
647 648 649 650 651 652 653 | ** of the corresponding length. As required to calculate the contents ** of the sqlite_stat1 entry. ** ** Currently, the last memory cell allocated (that with the largest ** integer identifier) is regStat4. Immediately following regStat4 ** we allocate the following: ** | < < < < < | < < | < | | | 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 | ** of the corresponding length. As required to calculate the contents ** of the sqlite_stat1 entry. ** ** Currently, the last memory cell allocated (that with the largest ** integer identifier) is regStat4. Immediately following regStat4 ** we allocate the following: ** ** regEq - nCol registers ** regLt - nCol registers ** regDLte - nCol registers ** regPrev - nCol registers ** ** The regRowid, regEq, regLt and regDLte registers must be positioned in ** that order immediately following regStat4 so that they can be passed ** to the stat4_push() function. ** ** All of the above are initialized to contain integer value 0. */ regEq = regRowid+1; /* First in array of nEq value registers */ regLt = regEq+nCol; /* First in array of nLt value registers */ regDLte = regLt+nCol; /* First in array of nDLt value registers */ regPrev = regDLte+nCol; /* First in array of prev. value registers */ pParse->nMem = MAX(pParse->nMem, regPrev+nCol); /* Open a read-only cursor for each column of the index. */ assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) ); iIdxCur = iTab; pParse->nTab = MAX(pParse->nTab, iTab+nCol); for(i=0; i<nCol; i++){ int iMode = (i==0 ? P4_KEYINFO_HANDOFF : P4_KEYINFO); sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur+i, pIdx->tnum, iDb); sqlite3VdbeChangeP4(v, -1, (char*)pKey, iMode); VdbeComment((v, "%s", pIdx->zName)); } |
︙ | ︙ | |||
699 700 701 702 703 704 705 | sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_STAT4_SAMPLES, regStat4+3); sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4); sqlite3VdbeChangeP4(v, -1, (char*)&stat4InitFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 3); #endif /* SQLITE_ENABLE_STAT4 */ /* Initialize all the memory registers allocated above to 0. */ | | > > | 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 | sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_STAT4_SAMPLES, regStat4+3); sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4); sqlite3VdbeChangeP4(v, -1, (char*)&stat4InitFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 3); #endif /* SQLITE_ENABLE_STAT4 */ /* Initialize all the memory registers allocated above to 0. */ for(i=regEq; i<regDLte+nCol; i++){ sqlite3VdbeAddOp2(v, OP_Integer, 0, i); } sqlite3VdbeAddOp2(v, OP_Integer, 0, regCnt); sqlite3VdbeAddOp2(v, OP_Integer, 0, regEof); /* Rewind all cursors open on the index. If the table is entry, this ** will cause control to jump to address endOfScan immediately. */ endOfScan = sqlite3VdbeMakeLabel(v); for(i=0; i<nCol; i++){ sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur+i, endOfScan); } |
︙ | ︙ | |||
769 770 771 772 773 774 775 | VdbeComment((v, "if( regPrev(%d) != csr(%d)(%d) )", j, i, j)); } sqlite3VdbeAddOp2(v, OP_Goto, 0, iDo); sqlite3VdbeResolveLabel(v, iNe); } /* Invoke stat4_push() */ | | < < < < < < | | | | 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 | VdbeComment((v, "if( regPrev(%d) != csr(%d)(%d) )", j, i, j)); } sqlite3VdbeAddOp2(v, OP_Goto, 0, iDo); sqlite3VdbeResolveLabel(v, iNe); } /* Invoke stat4_push() */ sqlite3VdbeAddOp3(v, OP_Function, 1, regStat4, regTemp); sqlite3VdbeChangeP4(v, -1, (char*)&stat4PushFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 2 + 3*nCol); sqlite3VdbeAddOp2(v, OP_If, regEof, endOfScan); for(i=0; i<nCol-1; i++){ char *pColl = (char*)sqlite3LocateCollSeq(pParse, pIdx->azColl[i]); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur+nCol-1, i, regCol); sqlite3VdbeAddOp3(v, OP_Ne, regCol, aChngAddr[i], regPrev+i); sqlite3VdbeChangeP4(v, -1, pColl, P4_COLLSEQ); sqlite3VdbeChangeP5(v, SQLITE_NULLEQ); } sqlite3VdbeAddOp2(v, OP_Goto, 0, aChngAddr[nCol-1]); sqlite3DbFree(db, aChngAddr); sqlite3VdbeResolveLabel(v, endOfScan); #ifdef SQLITE_ENABLE_STAT4 /* Add rows to the sqlite_stat4 table */ regLoop = regStat4+1; sqlite3VdbeAddOp2(v, OP_Integer, -1, regLoop); shortJump = sqlite3VdbeAddOp2(v, OP_AddImm, regLoop, 1); sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4, regTemp); sqlite3VdbeChangeP4(v, -1, (char*)&stat4GetFuncdef, P4_FUNCDEF); sqlite3VdbeChangeP5(v, 2); sqlite3VdbeAddOp1(v, OP_IsNull, regTemp); sqlite3VdbeAddOp3(v, OP_NotExists, iTabCur, shortJump, regTemp); for(i=0; i<nCol; i++){ int iCol = pIdx->aiColumn[i]; sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regPrev+i); } sqlite3VdbeAddOp3(v, OP_MakeRecord, regPrev, nCol, regSample); sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0); |
︙ | ︙ | |||
880 881 882 883 884 885 886 | sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeJumpHere(v, jZeroRows); } | < < < < < | 862 863 864 865 866 867 868 869 870 871 872 873 874 875 | sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regNewRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeJumpHere(v, jZeroRows); } } /* ** Generate code that will cause the most recent index analysis to ** be loaded into internal hash tables where is can be used. */ |
︙ | ︙ | |||
908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 | */ static void analyzeDatabase(Parse *pParse, int iDb){ sqlite3 *db = pParse->db; Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ HashElem *k; int iStatCur; int iMem; sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; pParse->nTab += 3; openStatTable(pParse, iDb, iStatCur, 0, 0); iMem = pParse->nMem+1; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ Table *pTab = (Table*)sqliteHashData(k); | > > | | 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 | */ static void analyzeDatabase(Parse *pParse, int iDb){ sqlite3 *db = pParse->db; Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ HashElem *k; int iStatCur; int iMem; int iTab; sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab; pParse->nTab += 3; openStatTable(pParse, iDb, iStatCur, 0, 0); iMem = pParse->nMem+1; iTab = pParse->nTab; assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ Table *pTab = (Table*)sqliteHashData(k); analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab); } loadAnalysis(pParse, iDb); } /* ** Generate code that will do an analysis of a single table in ** a database. If pOnlyIdx is not NULL then it is a single index |
︙ | ︙ | |||
942 943 944 945 946 947 948 | iStatCur = pParse->nTab; pParse->nTab += 3; if( pOnlyIdx ){ openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx"); }else{ openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl"); } | | | 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 | iStatCur = pParse->nTab; pParse->nTab += 3; if( pOnlyIdx ){ openStatTable(pParse, iDb, iStatCur, pOnlyIdx->zName, "idx"); }else{ openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl"); } analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur,pParse->nMem+1,pParse->nTab); loadAnalysis(pParse, iDb); } /* ** Generate code for the ANALYZE command. The parser calls this routine ** when it recognizes an ANALYZE command. ** |
︙ | ︙ |