/ Check-in [ecaac28a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Performance optimization to the OP_Next and OP_Prev opcodes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:ecaac28a2e78aca148fc614fe54bf2706aed8be2
User & Date: drh 2013-11-21 03:12:25
Context
2013-11-21
03:43
A simple change to the OP_Function opcode improves overall performance by about 0.5%. check-in: b890eefd user: drh tags: trunk
03:12
Performance optimization to the OP_Next and OP_Prev opcodes. check-in: ecaac28a user: drh tags: trunk
01:33
Refactor the OP_Column opcode to make it clearer and easier to maintain. Overall, performance tests show about a 1% speed increase with this change. check-in: 972881c6 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

4463
4464
4465
4466
4467
4468
4469
4470

4471
4472
4473
4474
4475
4476
4477
4478





4479
4480
4481
4482
4483
4484
4485
4486
4487

4488
4489
4490
4491
4492
4493
4494
4495
4496
4497



4498
4499
4500










4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512

4513
4514
4515
4516


4517
4518
4519

4520
4521

4522
4523
4524
4525
4526


4527
4528
4529
4530
4531
4532
4533
/* Opcode: Next P1 P2 * * P5
**
** Advance cursor P1 so that it points to the next key/data pair in its
** table or index.  If there are no more key/value pairs then fall through
** to the following instruction.  But if the cursor advance was successful,
** jump immediately to P2.
**
** The P1 cursor must be for a real table, not a pseudo-table.

**
** P4 is always of type P4_ADVANCE. The function pointer points to
** sqlite3BtreeNext().
**
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
**
** See also: Prev





*/
/* Opcode: Prev P1 P2 * * P5
**
** Back up cursor P1 so that it points to the previous key/data pair in its
** table or index.  If there is no previous key/value pairs then fall through
** to the following instruction.  But if the cursor backup was successful,
** jump immediately to P2.
**
** The P1 cursor must be for a real table, not a pseudo-table.

**
** P4 is always of type P4_ADVANCE. The function pointer points to
** sqlite3BtreePrevious().
**
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
*/
case OP_SorterNext:    /* jump */
case OP_Prev:          /* jump */
case OP_Next: {        /* jump */



  VdbeCursor *pC;
  int res;











  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( pOp->p5<ArraySize(p->aCounter) );
  pC = p->apCsr[pOp->p1];
  if( pC==0 ){
    break;  /* See ticket #2273 */
  }
  assert( isSorter(pC)==(pOp->opcode==OP_SorterNext) );
  if( isSorter(pC) ){
    assert( pOp->opcode==OP_SorterNext );
    rc = sqlite3VdbeSorterNext(db, pC, &res);
  }else{
    /* res = 1; // Always initialized by the xAdvance() call */

    assert( pC->deferredMoveto==0 );
    assert( pC->pCursor );
    assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
    assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );


    rc = pOp->p4.xAdvance(pC->pCursor, &res);
  }
  pC->nullRow = (u8)res;

  pC->cacheStatus = CACHE_STALE;
  if( res==0 ){

    pc = pOp->p2 - 1;
    p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
    sqlite3_search_count++;
#endif


  }
  pC->rowidIsValid = 0;
  goto check_for_interrupt;
}

/* Opcode: IdxInsert P1 P2 P3 * P5
** Synopsis: key=r[P2]







|
>







|
>
>
>
>
>








|
>







|
|
|
>
>
>



>
>
>
>
>
>
>
>
>
>



<
<
<
<
<
<
<
<
<
>
|
|
|
|
>
>
|
<
<
>


>





>
>







4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523









4524
4525
4526
4527
4528
4529
4530
4531


4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
/* Opcode: Next P1 P2 * * P5
**
** Advance cursor P1 so that it points to the next key/data pair in its
** table or index.  If there are no more key/value pairs then fall through
** to the following instruction.  But if the cursor advance was successful,
** jump immediately to P2.
**
** The P1 cursor must be for a real table, not a pseudo-table.  P1 must have
** been opened prior to this opcode or the program will segfault.
**
** P4 is always of type P4_ADVANCE. The function pointer points to
** sqlite3BtreeNext().
**
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
**
** See also: Prev, NextIfOpen
*/
/* Opcode: NextIfOpen P1 P2 * * P5
**
** This opcode works just like OP_Next except that if cursor P1 is not
** open it behaves a no-op.
*/
/* Opcode: Prev P1 P2 * * P5
**
** Back up cursor P1 so that it points to the previous key/data pair in its
** table or index.  If there is no previous key/value pairs then fall through
** to the following instruction.  But if the cursor backup was successful,
** jump immediately to P2.
**
** The P1 cursor must be for a real table, not a pseudo-table.  If P1 is
** not open then the behavior is undefined.
**
** P4 is always of type P4_ADVANCE. The function pointer points to
** sqlite3BtreePrevious().
**
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
*/
/* Opcode: PrevIfOpen P1 P2 * * P5
**
** This opcode works just like OP_Prev except that if cursor P1 is not
** open it behaves a no-op.
*/
case OP_SorterNext: {  /* jump */
  VdbeCursor *pC;
  int res;

  pC = p->apCsr[pOp->p1];
  assert( isSorter(pC) );
  rc = sqlite3VdbeSorterNext(db, pC, &res);
  goto next_tail;
case OP_PrevIfOpen:    /* jump */
case OP_NextIfOpen:    /* jump */
  if( p->apCsr[pOp->p1]==0 ) break;
  /* Fall through */
case OP_Prev:          /* jump */
case OP_Next:          /* jump */
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( pOp->p5<ArraySize(p->aCounter) );
  pC = p->apCsr[pOp->p1];









  assert( pC!=0 );
  assert( pC->deferredMoveto==0 );
  assert( pC->pCursor );
  assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
  assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
  assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
  assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious);
  rc = pOp->p4.xAdvance(pC->pCursor, &res);


next_tail:
  pC->cacheStatus = CACHE_STALE;
  if( res==0 ){
    pC->nullRow = 0;
    pc = pOp->p2 - 1;
    p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
    sqlite3_search_count++;
#endif
  }else{
    pC->nullRow = 1;
  }
  pC->rowidIsValid = 0;
  goto check_for_interrupt;
}

/* Opcode: IdxInsert P1 P2 P3 * P5
** Synopsis: key=r[P2]

Changes to src/vdbeaux.c.

449
450
451
452
453
454
455

456
457
458
459
460
461

462
463
464
465
466
467
468
        assert( pOp[-1].opcode==OP_Integer );
        n = pOp[-1].p1;
        if( n>nMaxArgs ) nMaxArgs = n;
        break;
      }
#endif
      case OP_Next:

      case OP_SorterNext: {
        pOp->p4.xAdvance = sqlite3BtreeNext;
        pOp->p4type = P4_ADVANCE;
        break;
      }
      case OP_Prev: {

        pOp->p4.xAdvance = sqlite3BtreePrevious;
        pOp->p4type = P4_ADVANCE;
        break;
      }
    }

    pOp->opflags = sqlite3OpcodeProperty[opcode];







>





|
>







449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
        assert( pOp[-1].opcode==OP_Integer );
        n = pOp[-1].p1;
        if( n>nMaxArgs ) nMaxArgs = n;
        break;
      }
#endif
      case OP_Next:
      case OP_NextIfOpen:
      case OP_SorterNext: {
        pOp->p4.xAdvance = sqlite3BtreeNext;
        pOp->p4type = P4_ADVANCE;
        break;
      }
      case OP_Prev:
      case OP_PrevIfOpen: {
        pOp->p4.xAdvance = sqlite3BtreePrevious;
        pOp->p4type = P4_ADVANCE;
        break;
      }
    }

    pOp->opflags = sqlite3OpcodeProperty[opcode];

Changes to src/where.c.

2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
      pIn += pLevel->u.in.nIn - 1;
      pIn->iCur = iTab;
      if( eType==IN_INDEX_ROWID ){
        pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
      }else{
        pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
      }
      pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
      sqlite3VdbeAddOp1(v, OP_IsNull, iReg);
    }else{
      pLevel->u.in.nIn = 0;
    }
#endif
  }
  disableTerm(pLevel, pTerm);







|







2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
      pIn += pLevel->u.in.nIn - 1;
      pIn->iCur = iTab;
      if( eType==IN_INDEX_ROWID ){
        pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg);
      }else{
        pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
      }
      pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
      sqlite3VdbeAddOp1(v, OP_IsNull, iReg);
    }else{
      pLevel->u.in.nIn = 0;
    }
#endif
  }
  disableTerm(pLevel, pTerm);