mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-11 01:42:22 +03:00
Comment improvements to on the distinct-agg optimization. Show a line in
the EQP output when using an ephemeral table to implement DISTINCT on an aggregate. FossilOrigin-Name: 037ca79e6032ca962b4f6182187bc12a7d91170d73630c8cd6fb191d2c183ee4
This commit is contained in:
55
src/select.c
55
src/select.c
@@ -748,6 +748,9 @@ static void codeOffset(
|
||||
** as follows:
|
||||
**
|
||||
** WHERE_DISTINCT_UNORDERED/WHERE_DISTINCT_NOOP:
|
||||
** Build an ephemeral table that contains all entries seen before and
|
||||
** skip entries which have been seen before.
|
||||
**
|
||||
** Parameter iTab is the cursor number of an ephemeral table that must
|
||||
** be opened before the VM code generated by this routine is executed.
|
||||
** The ephemeral cursor table is queried for a record identical to the
|
||||
@@ -758,20 +761,21 @@ static void codeOffset(
|
||||
** The returned value in this case is a copy of parameter iTab.
|
||||
**
|
||||
** WHERE_DISTINCT_ORDERED:
|
||||
** In this case rows are being delivered sorted order sorted. The ephermal
|
||||
** table is not required in this case. Instead, the current set of
|
||||
** registers are compared to previous row. If they match, the new row
|
||||
** In this case rows are being delivered sorted order. The ephermal
|
||||
** table is not required. Instead, the current set of values
|
||||
** is compared against previous row. If they match, the new row
|
||||
** is not distinct and control jumps to VM address addrRepeat. Otherwise,
|
||||
** the VM program proceeds with processing the new row.
|
||||
**
|
||||
** The returned value in this case is the register number of the first
|
||||
** in an array of registers used to store the previous result row so that
|
||||
** it can be compared to the next. The caller must ensure that this cell
|
||||
** is initialized to NULL and has the "clear" flag set.
|
||||
** it can be compared to the next. The caller must ensure that this
|
||||
** register is initialized to NULL. (The fixDistinctOpenEph() routine
|
||||
** will take care of this initialization.)
|
||||
**
|
||||
** WHERE_DISTINCT_UNIQUE:
|
||||
** In this case it has already been determined that the rows are distinct.
|
||||
** No special action is required. The return value is always zero.
|
||||
** No special action is required. The return value is zero.
|
||||
**
|
||||
** Parameter pEList is the list of expressions used to generated the
|
||||
** contents of each row. It is used by this routine to determine (a)
|
||||
@@ -841,25 +845,27 @@ static int codeDistinct(
|
||||
}
|
||||
|
||||
/*
|
||||
** A call to this function must be made for each call to codeDistinct().
|
||||
** Parameter is passed the value returned by that call to codeDistinct(),
|
||||
** and iOpenEphAddr the address of the instruction used to open the
|
||||
** ephemeral table (that may be) used by codeDistinct().
|
||||
** This routine runs after codeDistinct(). It makes necessary
|
||||
** adjustments to the OP_OpenEphemeral opcode that the codeDistinct()
|
||||
** routine made use of. This processing must be done separately since
|
||||
** sometimes codeDistinct is called before the OP_OpenEphemeral is actually
|
||||
** laid down.
|
||||
**
|
||||
** Argument eTnctType is passed the strategy to be used for any DISTINCT
|
||||
** operation, as returned by sqlite3WhereIsDistinct(). If the strategy
|
||||
** is WHERE_DISTINCT_NOOP or WHERE_DISTINCT_UNORDERED, this function is
|
||||
** a no-op. Otherwise:
|
||||
** WHERE_DISTINCT_NOOP:
|
||||
** WHERE_DISTINCT_UNORDERED:
|
||||
**
|
||||
** WHERE_DISTINCT_UNIQUE:
|
||||
** In this case the ephemeral table is not required. So instruction
|
||||
** iOpenEphAddr is replaced by an OP_Noop.
|
||||
** No adjustments necessary. This function is a no-op.
|
||||
**
|
||||
** WHERE_DISTINCT_ORDERED:
|
||||
** In this case the ephemeral table is not required. The instruction
|
||||
** iOpenEphAddr is replaced by an OP_Null instruction to set register
|
||||
** iVal to a NULL value with the "clear" flag set (see comments above
|
||||
** codeDistinct() for details).
|
||||
** WHERE_DISTINCT_UNIQUE:
|
||||
**
|
||||
** The ephemeral table is not needed. So change the
|
||||
** OP_OpenEphemeral opcode into an OP_Noop.
|
||||
**
|
||||
** WHERE_DISTINCT_ORDERED:
|
||||
**
|
||||
** The ephemeral table is not needed. But we do need register
|
||||
** iVal to be initialized to NULL. So change the OP_OpenEphemeral
|
||||
** into an OP_Null on the iVal register.
|
||||
*/
|
||||
static void fixDistinctOpenEph(
|
||||
Parse *pParse, /* Parsing and code generating context */
|
||||
@@ -870,6 +876,9 @@ static void fixDistinctOpenEph(
|
||||
if( eTnctType==WHERE_DISTINCT_UNIQUE || eTnctType==WHERE_DISTINCT_ORDERED ){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
sqlite3VdbeChangeToNoop(v, iOpenEphAddr);
|
||||
if( sqlite3VdbeGetOp(v, iOpenEphAddr+1)->opcode==OP_Explain ){
|
||||
sqlite3VdbeChangeToNoop(v, iOpenEphAddr+1);
|
||||
}
|
||||
if( eTnctType==WHERE_DISTINCT_ORDERED ){
|
||||
/* Change the OP_OpenEphemeral to an OP_Null that sets the MEM_Cleared
|
||||
** bit on the first register of the previous value. This will cause the
|
||||
@@ -5714,6 +5723,8 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
KeyInfo *pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pE->x.pList,0,0);
|
||||
pFunc->iDistAddr = sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
|
||||
pFunc->iDistinct, 0, 0, (char*)pKeyInfo, P4_KEYINFO);
|
||||
ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(DISTINCT)",
|
||||
pFunc->pFunc->zName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user