From: dan Date: Thu, 28 May 2015 19:57:12 +0000 (+0000) Subject: Optimizations for fts5 queries that match against a specific column. X-Git-Tag: version-3.8.11~114^2~26 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e96efb642633606c5c87ef3649e7fe183158b601;p=thirdparty%2Fsqlite.git Optimizations for fts5 queries that match against a specific column. FossilOrigin-Name: b29ac50af0491a780a5a4c0985d88d0e5e014ba3 --- diff --git a/ext/fts5/fts5_expr.c b/ext/fts5/fts5_expr.c index 945bb637f8..891bb30382 100644 --- a/ext/fts5/fts5_expr.c +++ b/ext/fts5/fts5_expr.c @@ -652,6 +652,45 @@ static int fts5ExprNearNextRowidMatch( return rc; } +/* +** IN/OUT parameter (*pa) points to a position list n bytes in size. If +** the position list contains entries for column iCol, then (*pa) is set +** to point to the sub-position-list for that column and the number of +** bytes in it returned. Or, if the argument position list does not +** contain any entries for column iCol, return 0. +*/ +static int fts5ExprExtractCol( + const u8 **pa, /* IN/OUT: Pointer to poslist */ + int n, /* IN: Size of poslist in bytes */ + int iCol /* Column to extract from poslist */ +){ + int ii; + int iCurrent = 0; + const u8 *p = *pa; + const u8 *pEnd = &p[n]; /* One byte past end of position list */ + u8 prev = 0; + + while( iCol!=iCurrent ){ + /* Advance pointer p until it points to pEnd or an 0x01 byte that is + ** not part of a varint */ + while( !(prev & 0x80) && *p!=0x01 ){ + prev = *p++; + if( p==pEnd ) return 0; + } + *pa = p++; + p += getVarint32(p, iCurrent); + } + + /* Advance pointer p until it points to pEnd or an 0x01 byte that is + ** not part of a varint */ + while( ppNear; + int rc = SQLITE_OK; - if( pNear->nPhrase==1 - && pNear->apPhrase[0]->nTerm==1 - && pNear->iCol<0 - ){ - /* If this "NEAR" object is actually a single phrase that consists of - ** a single term only, then the row that it currently points to must - ** be a match. All that is required is to populate pPhrase->poslist - ** with the position-list data for the only term. */ - Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; - Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; - assert( pPhrase->poslist.nSpace==0 ); - return sqlite3Fts5IterPoslist(pIter, - (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid - ); - }else{ - int rc = SQLITE_OK; + while( 1 ){ + int i; - while( 1 ){ - int i; + if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 ){ + /* If this "NEAR" object is actually a single phrase that consists + ** of a single term only, then grab pointers into the poslist + ** managed by the fts5_index.c iterator object. This is much faster + ** than synthesizing a new poslist the way we have to for more + ** complicated phrase or NEAR expressions. */ + Fts5ExprPhrase *pPhrase = pNear->apPhrase[0]; + Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter; + assert( pPhrase->poslist.nSpace==0 ); + rc = sqlite3Fts5IterPoslist(pIter, + (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid + ); + + /* If the term may match any column, then this must be a match. + ** Return immediately in this case. Otherwise, try to find the + ** part of the poslist that corresponds to the required column. + ** If it can be found, return. If it cannot, the next iteration + ** of the loop will test the next rowid in the database for this + ** term. */ + if( pNear->iCol<0 ) return rc; + + pPhrase->poslist.n = fts5ExprExtractCol( + (const u8**)&pPhrase->poslist.p, + pPhrase->poslist.n, + pNear->iCol + ); + if( pPhrase->poslist.n ) return rc; + }else{ /* Advance the iterators until they all point to the same rowid */ rc = fts5ExprNearNextRowidMatch(pExpr, pNode); @@ -711,7 +763,7 @@ static int fts5ExprNearNextMatch( }else{ rc = sqlite3Fts5IterPoslistBuffer( pPhrase->aTerm[0].pIter, &pPhrase->poslist - ); + ); } } @@ -722,17 +774,17 @@ static int fts5ExprNearNextMatch( } if( rc!=SQLITE_OK || bMatch ) break; } - - /* If control flows to here, then the current rowid is not a match. - ** Advance all term iterators in all phrases to the next rowid. */ - if( rc==SQLITE_OK ){ - rc = fts5ExprNearAdvanceFirst(pExpr, pNode, 0, 0); - } - if( pNode->bEof || rc!=SQLITE_OK ) break; } - return rc; + /* If control flows to here, then the current rowid is not a match. + ** Advance all term iterators in all phrases to the next rowid. */ + if( rc==SQLITE_OK ){ + rc = fts5ExprNearAdvanceFirst(pExpr, pNode, 0, 0); + } + if( pNode->bEof || rc!=SQLITE_OK ) break; } + + return rc; } /* diff --git a/ext/fts5/test/fts5aa.test b/ext/fts5/test/fts5aa.test index 800215d2bb..e7c37ccbf8 100644 --- a/ext/fts5/test/fts5aa.test +++ b/ext/fts5/test/fts5aa.test @@ -426,6 +426,12 @@ do_test 17.2 { set res } {{a b c} {a b c} {a b c}} +reset_db +do_execsql_test 18.1 { + CREATE VIRTUAL TABLE c2 USING fts5(x, y); + INSERT INTO c2 VALUES('x x x', 'x x x'); + SELECT rowid FROM c2 WHERE c2 MATCH 'y:x'; +} {1} finish_test diff --git a/manifest b/manifest index 328ed4e922..887ea5a8a5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\ssome\sdead\scode\sfrom\sfts5.\sAdd\sauxiliary\sfunction\sapi\stests\sto\sthe\ssame. -D 2015-05-28T14:37:26.732 +C Optimizations\sfor\sfts5\squeries\sthat\smatch\sagainst\sa\sspecific\scolumn. +D 2015-05-28T19:57:12.367 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2c28e557780395095c307a6e5cb539419027eb5e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -111,7 +111,7 @@ F ext/fts5/fts5Int.h 2ce5c5e68852dd16de404b7a9a2a78f4f4588eb4 F ext/fts5/fts5_aux.c d53f00f31ad615ca4f139dd8751f9041afa00971 F ext/fts5/fts5_buffer.c 861599a0abe2383f0cd0352c57001140a26b0930 F ext/fts5/fts5_config.c 11f969ed711a0a8b611d47431d74c372ad78c713 -F ext/fts5/fts5_expr.c a8b31d363c02108dae01e13948661859f449ebb9 +F ext/fts5/fts5_expr.c c94983eaff58391d7c0d62e99de917cecd0f1dbc F ext/fts5/fts5_hash.c 54dd25348a46ea62ea96322c572e08cd1fb37304 F ext/fts5/fts5_index.c a693ba741b82539da5779329214e5d2609e82e5f F ext/fts5/fts5_storage.c 5d2b51adb304643d8f825ba89283d628418b20c2 @@ -122,7 +122,7 @@ F ext/fts5/fts5_vocab.c 1f8543b2c1ae4427f127a911bc8e60873fcd7bf9 F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9 F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba F ext/fts5/test/fts5_common.tcl 6d663e8c3d8409857363f66560df96b8ca813e79 -F ext/fts5/test/fts5aa.test 26f1a462213f3aa067c208bd508d6218c54a620f +F ext/fts5/test/fts5aa.test 5f73afe6a1394fdba9bc18302876ded81021bee6 F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad F ext/fts5/test/fts5ac.test 05008e00bd2761cc45df838a0988ecf318cbe1fd F ext/fts5/test/fts5ad.test 312f3c8ed9592533499c5b94d2059ae6382913a0 @@ -1331,7 +1331,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P aef89d9f6aa536efee347367558cf5d4ea81b238 -R bb8e2d4390fd848d148991824b1dfd3a +P 0f9df202cc58097afddb8dad662b7c7fdc2c7d0c +R f25569d3bfd1393da78f5986e0e8acff U dan -Z cb932577f097e506aa4f837dda1f2a1b +Z d652fde1b36e85f62688dc3a9737ccda diff --git a/manifest.uuid b/manifest.uuid index d0242f4b60..4025ca1b11 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f9df202cc58097afddb8dad662b7c7fdc2c7d0c \ No newline at end of file +b29ac50af0491a780a5a4c0985d88d0e5e014ba3 \ No newline at end of file