Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge latest changes from trunk, and also move the perf-counter into the inner loop of sqlite3BtreeMovetoUnpacked(). |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | vdbe-aux-perf |
Files: | files | file ages | folders |
SHA1: |
ff9eab95879038ab3015b93f637f6d93 |
User & Date: | drh 2017-01-09 20:57:38.218 |
Context
2017-01-09
| ||
20:57 | Merge latest changes from trunk, and also move the perf-counter into the inner loop of sqlite3BtreeMovetoUnpacked(). (Leaf check-in: ff9eab9587 user: drh tags: vdbe-aux-perf) | |
19:55 | Remove a redundant assignment statement. (check-in: a5fa09657b user: drh tags: trunk) | |
2017-01-07
| ||
00:42 | This hack illustrates how to use the VDBE_PROFILE mechanism to show which bytecode operators are using resources other than time. In this case, the number of loops through the binary search code in sqlite3BtreeMovetoUnpacked() is measured, for the purpose of helping to identify unnecessary btree searches. (check-in: 746b183683 user: drh tags: vdbe-aux-perf) | |
Changes
Changes to src/btree.c.
︙ | ︙ | |||
5120 5121 5122 5123 5124 5125 5126 | assert( pCur->apPage[0]->intKey==pCur->curIntKey ); assert( pCur->curIntKey || pIdxKey ); for(;;){ int lwr, upr, idx, c; Pgno chldPg; MemPage *pPage = pCur->apPage[pCur->iPage]; u8 *pCell; /* Pointer to current cell in pPage */ | < > | 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 | assert( pCur->apPage[0]->intKey==pCur->curIntKey ); assert( pCur->curIntKey || pIdxKey ); for(;;){ int lwr, upr, idx, c; Pgno chldPg; MemPage *pPage = pCur->apPage[pCur->iPage]; u8 *pCell; /* Pointer to current cell in pPage */ /* pPage->nCell must be greater than zero. If this is the root-page ** the cursor would have been INVALID above and this for(;;) loop ** not run. If this is not the root-page, then the moveToChild() routine ** would have already detected db corruption. Similarly, pPage must ** be the right kind (index or table) of b-tree page. Otherwise ** a moveToChild() or moveToRoot() call would have detected corruption. */ assert( pPage->nCell>0 ); assert( pPage->intKey==(pIdxKey==0) ); lwr = 0; upr = pPage->nCell-1; assert( biasRight==0 || biasRight==1 ); idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */ pCur->aiIdx[pCur->iPage] = (u16)idx; if( xRecordCompare==0 ){ for(;;){ i64 nCellKey; sqlite3PerfCnt++; pCell = findCellPastPtr(pPage, idx); if( pPage->intKeyLeaf ){ while( 0x80 <= *(pCell++) ){ if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT; } } getVarint(pCell, (u64*)&nCellKey); |
︙ | ︙ | |||
5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 | } assert( lwr+upr>=0 ); idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ } }else{ for(;;){ int nCell; /* Size of the pCell cell in bytes */ pCell = findCellPastPtr(pPage, idx); /* The maximum supported page-size is 65536 bytes. This means that ** the maximum number of record bytes stored on an index B-Tree ** page is less than 16384 bytes and may be stored as a 2-byte ** varint. This information is used to attempt to avoid parsing ** the entire cell by checking for the cases where the record is | > | 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 | } assert( lwr+upr>=0 ); idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */ } }else{ for(;;){ int nCell; /* Size of the pCell cell in bytes */ sqlite3PerfCnt++; pCell = findCellPastPtr(pPage, idx); /* The maximum supported page-size is 65536 bytes. This means that ** the maximum number of record bytes stored on an index B-Tree ** page is less than 16384 bytes and may be stored as a 2-byte ** varint. This information is used to attempt to avoid parsing ** the entire cell by checking for the cases where the record is |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
515 516 517 518 519 520 521 | if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){ pParse->isMultiWrite = 0; } }else #endif { int count = (pParse->nested==0); /* True to count changes */ | < < < < | | 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | if( eOnePass==ONEPASS_SINGLE && sqlite3IsToplevel(pParse) ){ pParse->isMultiWrite = 0; } }else #endif { int count = (pParse->nested==0); /* True to count changes */ sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, iKey, nKey, count, OE_Default, eOnePass, aiCurOnePass[1]); } /* End of the loop over all rowids/primary-keys. */ if( eOnePass!=ONEPASS_OFF ){ sqlite3VdbeResolveLabel(v, addrBypass); sqlite3WhereEnd(pWInfo); }else if( pPk ){ |
︙ | ︙ | |||
600 601 602 603 604 605 606 | ** ONEPASS_MULTI. If eMode is not ONEPASS_OFF, then the cursor ** iDataCur already points to the row to delete. If eMode is ONEPASS_OFF ** then this function must seek iDataCur to the entry identified by iPk ** and nPk before reading from it. ** ** If eMode is ONEPASS_MULTI, then this call is being made as part ** of a ONEPASS delete that affects multiple rows. In this case, if | | > | | < | | | > > | 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 | ** ONEPASS_MULTI. If eMode is not ONEPASS_OFF, then the cursor ** iDataCur already points to the row to delete. If eMode is ONEPASS_OFF ** then this function must seek iDataCur to the entry identified by iPk ** and nPk before reading from it. ** ** If eMode is ONEPASS_MULTI, then this call is being made as part ** of a ONEPASS delete that affects multiple rows. In this case, if ** iIdxNoSeek is a valid cursor number (>=0) and is not the same as ** iDataCur, then its position should be preserved following the delete ** operation. Or, if iIdxNoSeek is not a valid cursor number, the ** position of iDataCur should be preserved instead. ** ** iIdxNoSeek: ** If iIdxNoSeek is a valid cursor number (>=0) not equal to iDataCur, ** then it identifies an index cursor (from within array of cursors ** starting at iIdxCur) that already points to the index entry to be deleted. ** Except, this optimization is disabled if there are BEFORE triggers since ** the trigger body might have moved the cursor. */ void sqlite3GenerateRowDelete( Parse *pParse, /* Parsing context */ Table *pTab, /* Table containing the row to be deleted */ Trigger *pTrigger, /* List of triggers to (potentially) fire */ int iDataCur, /* Cursor from which column data is extracted */ int iIdxCur, /* First index cursor */ |
︙ | ︙ | |||
679 680 681 682 683 684 685 | addrStart = sqlite3VdbeCurrentAddr(v); sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel ); /* If any BEFORE triggers were coded, then seek the cursor to the ** row to be deleted again. It may be that the BEFORE triggers moved | | > > > > > | 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 | addrStart = sqlite3VdbeCurrentAddr(v); sqlite3CodeRowTrigger(pParse, pTrigger, TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel ); /* If any BEFORE triggers were coded, then seek the cursor to the ** row to be deleted again. It may be that the BEFORE triggers moved ** the cursor or already deleted the row that the cursor was ** pointing to. ** ** Also disable the iIdxNoSeek optimization since the BEFORE trigger ** may have moved that cursor. */ if( addrStart<sqlite3VdbeCurrentAddr(v) ){ sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk); VdbeCoverageIf(v, opSeek==OP_NotExists); VdbeCoverageIf(v, opSeek==OP_NotFound); testcase( iIdxNoSeek>=0 ); iIdxNoSeek = -1; } /* Do FK processing. This call checks that any FK constraints that ** refer to this table (i.e. constraints attached to other tables) ** are not violated by deleting this row. */ sqlite3FkCheck(pParse, pTab, iOld, 0, 0, 0); } |
︙ | ︙ | |||
712 713 714 715 716 717 718 | u8 p5 = 0; sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE); if( eMode!=ONEPASS_OFF ){ sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE); } | | | 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 | u8 p5 = 0; sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur,0,iIdxNoSeek); sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0)); sqlite3VdbeAppendP4(v, (char*)pTab, P4_TABLE); if( eMode!=ONEPASS_OFF ){ sqlite3VdbeChangeP5(v, OPFLAG_AUXDELETE); } if( iIdxNoSeek>=0 && iIdxNoSeek!=iDataCur ){ sqlite3VdbeAddOp1(v, OP_Delete, iIdxNoSeek); } if( eMode==ONEPASS_MULTI ) p5 |= OPFLAG_SAVEPOSITION; sqlite3VdbeChangeP5(v, p5); } /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
1647 1648 1649 1650 1651 1652 1653 | assert( onError==OE_Replace ); sqlite3MultiWrite(pParse); if( db->flags&SQLITE_RecTriggers ){ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, | | | 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 | assert( onError==OE_Replace ); sqlite3MultiWrite(pParse); if( db->flags&SQLITE_RecTriggers ){ pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0); } sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur, regR, nPkField, 0, OE_Replace, (pIdx==pPk ? ONEPASS_SINGLE : ONEPASS_OFF), iThisCur); seenReplace = 1; break; } } sqlite3VdbeResolveLabel(v, addrUniqueOk); if( regR!=regIdx ) sqlite3ReleaseTempRange(pParse, regR, nPkField); } |
︙ | ︙ | |||
2134 2135 2136 2137 2138 2139 2140 | autoIncStep(pParse, regAutoinc, regRowid); }else if( pDest->pIndex==0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); }else{ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); assert( (pDest->tabFlags & TF_Autoincrement)==0 ); } | | | 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 | autoIncStep(pParse, regAutoinc, regRowid); }else if( pDest->pIndex==0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_NewRowid, iDest, regRowid); }else{ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, regRowid); assert( (pDest->tabFlags & TF_Autoincrement)==0 ); } sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); if( db->flags & SQLITE_Vacuum ){ sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1); insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID| OPFLAG_APPEND|OPFLAG_USESEEKRESULT; }else{ insFlags = OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND; } |
︙ | ︙ | |||
2166 2167 2168 2169 2170 2171 2172 | sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx); VdbeComment((v, "%s", pSrcIdx->zName)); sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest); sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); | | | 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 | sqlite3VdbeSetP4KeyInfo(pParse, pSrcIdx); VdbeComment((v, "%s", pSrcIdx->zName)); sqlite3VdbeAddOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum, iDbDest); sqlite3VdbeSetP4KeyInfo(pParse, pDestIdx); sqlite3VdbeChangeP5(v, OPFLAG_BULKCSR); VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_RowData, iSrc, regData, 1); if( db->flags & SQLITE_Vacuum ){ /* This INSERT command is part of a VACUUM operation, which guarantees ** that the destination table is empty. If all indexed columns use ** collation sequence BINARY, then it can also be assumed that the ** index will be populated by inserting keys in strictly sorted ** order. In this case, instead of seeking within the b-tree as part ** of every OP_IdxInsert opcode, an OP_Last is added before the |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
653 654 655 656 657 658 659 660 661 662 663 664 665 666 | int r1; v = pParse->pVdbe; r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N); sqlite3ReleaseTempReg(pParse, r1); } /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. ** | > | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 | int r1; v = pParse->pVdbe; r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4Int(v, OP_Found, iTab, addrRepeat, iMem, N); VdbeCoverage(v); sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1); sqlite3VdbeAddOp4Int(v, OP_IdxInsert, iTab, r1, iMem, N); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); sqlite3ReleaseTempReg(pParse, r1); } /* ** This routine generates the code for the inside of the inner loop ** of a SELECT. ** |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
255 256 257 258 259 260 261 | ** ^The sqlite3_int64 and sqlite_int64 types can store integer values ** between -9223372036854775808 and +9223372036854775807 inclusive. ^The ** sqlite3_uint64 and sqlite_uint64 types can store integer values ** between 0 and +18446744073709551615 inclusive. */ #ifdef SQLITE_INT64_TYPE typedef SQLITE_INT64_TYPE sqlite_int64; | > > > | > | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | ** ^The sqlite3_int64 and sqlite_int64 types can store integer values ** between -9223372036854775808 and +9223372036854775807 inclusive. ^The ** sqlite3_uint64 and sqlite_uint64 types can store integer values ** between 0 and +18446744073709551615 inclusive. */ #ifdef SQLITE_INT64_TYPE typedef SQLITE_INT64_TYPE sqlite_int64; # ifdef SQLITE_UINT64_TYPE typedef SQLITE_UINT64_TYPE sqlite_uint64; # else typedef unsigned SQLITE_INT64_TYPE sqlite_uint64; # endif #elif defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 sqlite_int64; typedef unsigned __int64 sqlite_uint64; #else typedef long long int sqlite_int64; typedef unsigned long long int sqlite_uint64; #endif |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
1192 1193 1194 1195 1196 1197 1198 | assert( pOp->p1>0 && pOp->p1<=p->nVar ); assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) ); pVar = &p->aVar[pOp->p1 - 1]; if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; } | | | 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 | assert( pOp->p1>0 && pOp->p1<=p->nVar ); assert( pOp->p4.z==0 || pOp->p4.z==sqlite3VListNumToName(p->pVList,pOp->p1) ); pVar = &p->aVar[pOp->p1 - 1]; if( sqlite3VdbeMemTooBig(pVar) ){ goto too_big; } pOut = &aMem[pOp->p2]; sqlite3VdbeMemShallowCopy(pOut, pVar, MEM_Static); UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Move P1 P2 P3 * * ** Synopsis: r[P2@P3]=r[P1@P3] |
︙ | ︙ | |||
4629 4630 4631 4632 4633 4634 4635 | assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); if( rc ) goto abort_due_to_error; p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE; break; } | | > > > > > > > > > > > > > | < | 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 | assert( rc!=SQLITE_OK || (pOut->flags & MEM_Blob) ); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); if( rc ) goto abort_due_to_error; p->apCsr[pOp->p3]->cacheStatus = CACHE_STALE; break; } /* Opcode: RowData P1 P2 P3 * * ** Synopsis: r[P2]=data ** ** Write into register P2 the complete row content for the row at ** which cursor P1 is currently pointing. ** There is no interpretation of the data. ** It is just copied onto the P2 register exactly as ** it is found in the database file. ** ** If cursor P1 is an index, then the content is the key of the row. ** If cursor P2 is a table, then the content extracted is the data. ** ** If the P1 cursor must be pointing to a valid row (not a NULL row) ** of a real table, not a pseudo-table. ** ** If P3!=0 then this opcode is allowed to make an ephermeral pointer ** into the database page. That means that the content of the output ** register will be invalidated as soon as the cursor moves - including ** moves caused by other cursors that "save" the the current cursors ** position in order that they can write to the same table. If P3==0 ** then a copy of the data is made into memory. P3!=0 is faster, but ** P3==0 is safer. ** ** If P3!=0 then the content of the P2 register is unsuitable for use ** in OP_Result and any OP_Result will invalidate the P2 register content. ** The P2 register content is invalidated by opcodes like OP_Function or ** by any use of another cursor pointing to the same table. */ case OP_RowData: { VdbeCursor *pC; BtCursor *pCrsr; u32 n; pOut = out2Prerelease(p, pOp); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->eCurType==CURTYPE_BTREE ); assert( isSorter(pC)==0 ); assert( pC->nullRow==0 ); |
︙ | ︙ | |||
4681 4682 4683 4684 4685 4686 4687 | #endif n = sqlite3BtreePayloadSize(pCrsr); if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } testcase( n==0 ); | < < < < < | < > | 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 | #endif n = sqlite3BtreePayloadSize(pCrsr); if( n>(u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){ goto too_big; } testcase( n==0 ); rc = sqlite3VdbeMemFromBtree(pCrsr, 0, n, pOut); if( rc ) goto abort_due_to_error; if( !pOp->p3 ) Deephemeralize(pOut); UPDATE_MAX_BLOBSIZE(pOut); REGISTER_TRACE(pOp->p2, pOut); break; } /* Opcode: Rowid P1 P2 * * * ** Synopsis: r[P2]=rowid |
︙ | ︙ | |||
5198 5199 5200 5201 5202 5203 5204 | pTabCur->deferredMoveto = 1; assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 ); pTabCur->aAltMap = pOp->p4.ai; pTabCur->pAltCursor = pC; }else{ pOut = out2Prerelease(p, pOp); pOut->u.i = rowid; | < | 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 | pTabCur->deferredMoveto = 1; assert( pOp->p4type==P4_INTARRAY || pOp->p4.ai==0 ); pTabCur->aAltMap = pOp->p4.ai; pTabCur->pAltCursor = pC; }else{ pOut = out2Prerelease(p, pOp); pOut->u.i = rowid; } }else{ assert( pOp->opcode==OP_IdxRowid ); sqlite3VdbeMemSetNull(&aMem[pOp->p2]); } break; } |
︙ | ︙ |