From: <di...@us...> - 2011-02-07 17:54:30
|
Revision: 52314 http://firebird.svn.sourceforge.net/firebird/?rev=52314&view=rev Author: dimitr Date: 2011-02-07 17:54:24 +0000 (Mon, 07 Feb 2011) Log Message: ----------- Implement CORE-3076: Better performance for (table.field = :param or :param = -1) in where clause. Modified Paths: -------------- firebird/trunk/builds/win32/msvc10/engine.vcxproj firebird/trunk/builds/win32/msvc8/engine.vcproj firebird/trunk/builds/win32/msvc9/engine.vcproj firebird/trunk/src/jrd/Optimizer.cpp firebird/trunk/src/jrd/Optimizer.h firebird/trunk/src/jrd/opt.cpp firebird/trunk/src/jrd/recsrc/RecordSource.h Added Paths: ----------- firebird/trunk/src/jrd/recsrc/ConditionalStream.cpp Modified: firebird/trunk/builds/win32/msvc10/engine.vcxproj =================================================================== --- firebird/trunk/builds/win32/msvc10/engine.vcxproj 2011-02-07 14:32:21 UTC (rev 52313) +++ firebird/trunk/builds/win32/msvc10/engine.vcxproj 2011-02-07 17:54:24 UTC (rev 52314) @@ -108,6 +108,7 @@ <ClCompile Include="..\..\..\src\jrd\recsrc\AggregatedStream.cpp" /> <ClCompile Include="..\..\..\src\jrd\recsrc\BitmapTableScan.cpp" /> <ClCompile Include="..\..\..\src\jrd\recsrc\BufferedStream.cpp" /> + <ClCompile Include="..\..\..\src\jrd\recsrc\ConditionalStream.cpp" /> <ClCompile Include="..\..\..\src\jrd\recsrc\Cursor.cpp" /> <ClCompile Include="..\..\..\src\jrd\recsrc\ExternalTableScan.cpp" /> <ClCompile Include="..\..\..\src\jrd\recsrc\FilteredStream.cpp" /> Modified: firebird/trunk/builds/win32/msvc8/engine.vcproj =================================================================== --- firebird/trunk/builds/win32/msvc8/engine.vcproj 2011-02-07 14:32:21 UTC (rev 52313) +++ firebird/trunk/builds/win32/msvc8/engine.vcproj 2011-02-07 17:54:24 UTC (rev 52314) @@ -619,6 +619,10 @@ > </File> <File + RelativePath="..\..\..\src\jrd\recsrc\ConditionalStream.cpp" + > + </File> + <File RelativePath="..\..\..\src\jrd\recsrc\Cursor.cpp" > </File> Modified: firebird/trunk/builds/win32/msvc9/engine.vcproj =================================================================== --- firebird/trunk/builds/win32/msvc9/engine.vcproj 2011-02-07 14:32:21 UTC (rev 52313) +++ firebird/trunk/builds/win32/msvc9/engine.vcproj 2011-02-07 17:54:24 UTC (rev 52314) @@ -619,6 +619,10 @@ > </File> <File + RelativePath="..\..\..\src\jrd\recsrc\ConditionalStream.cpp" + > + </File> + <File RelativePath="..\..\..\src\jrd\recsrc\Cursor.cpp" > </File> Modified: firebird/trunk/src/jrd/Optimizer.cpp =================================================================== --- firebird/trunk/src/jrd/Optimizer.cpp 2011-02-07 14:32:21 UTC (rev 52313) +++ firebird/trunk/src/jrd/Optimizer.cpp 2011-02-07 17:54:24 UTC (rev 52314) @@ -382,6 +382,7 @@ nonFullMatchedSegments = MAX_INDEX_SEGMENTS + 1; matchedSegments = 0; boolean = NULL; + condition = NULL; inversion = NULL; scratch = NULL; used = false; @@ -1341,7 +1342,7 @@ { // If this is a unique full equal matched inversion we're done, so // we can make the inversion and return it. - if (currentInv->unique && currentInv->dependencies) + if (currentInv->unique && currentInv->dependencies && !currentInv->condition) { if (!invCandidate) invCandidate = FB_NEW(pool) InversionCandidate(pool); @@ -1413,6 +1414,20 @@ } else { + // Prefer unconditional inversions + if (currentInv->condition) + { + currentInv->used = true; + restartLoop = true; + break; + } + else if (bestCandidate->condition) + { + bestCandidate = currentInv; + restartLoop = true; + break; + } + if (currentInv->unique && !bestCandidate->unique) { // A unique full equal match is better than anything else. @@ -1570,6 +1585,8 @@ invCandidate->nonFullMatchedSegments = 0; invCandidate->matchedSegments = bestCandidate->matchedSegments; invCandidate->dependencies = bestCandidate->dependencies; + invCandidate->condition = bestCandidate->condition; + for (size_t j = 0; j < bestCandidate->matches.getCount(); j++) { if (!matches.exist(bestCandidate->matches[j])) { @@ -1585,6 +1602,8 @@ } else { + fb_assert(!bestCandidate->condition); + if (!bestCandidate->inversion && bestCandidate->scratch) { invCandidate->inversion = composeInversion(invCandidate->inversion, @@ -2115,8 +2134,6 @@ getInversionCandidates(&inversions, &indexOrScratches, scope); invCandidate1 = makeInversion(&inversions); - if (!invCandidate1) - return NULL; // Clear list to remove previously matched conjunctions indexOrScratches.clear(); @@ -2148,7 +2165,7 @@ invCandidate2 = makeInversion(&inversions); - if (invCandidate2) + if (invCandidate1 && invCandidate2) { InversionCandidate* invCandidate = FB_NEW(pool) InversionCandidate(pool); invCandidate->inversion = composeInversion(invCandidate1->inversion, @@ -2162,6 +2179,23 @@ MIN(invCandidate1->matchedSegments, invCandidate2->matchedSegments); invCandidate->dependencies = invCandidate1->dependencies + invCandidate2->dependencies; + if (invCandidate1->condition && invCandidate2->condition) + { + BinaryBoolNode* const newNode = + FB_NEW(*tdbb->getDefaultPool()) BinaryBoolNode(*tdbb->getDefaultPool(), blr_or); + newNode->arg1 = invCandidate1->condition; + newNode->arg2 = invCandidate2->condition; + invCandidate->condition = newNode; + } + else if (invCandidate1->condition) + { + invCandidate->condition = invCandidate1->condition; + } + else if (invCandidate2->condition) + { + invCandidate->condition = invCandidate2->condition; + } + // Add matches conjunctions that exists in both left and right inversion if ((invCandidate1->matches.getCount()) && (invCandidate2->matches.getCount())) { @@ -2179,6 +2213,16 @@ return invCandidate; } + else if (invCandidate1) + { + invCandidate1->condition = binaryNode->arg2; + return invCandidate1; + } + else if (invCandidate2) + { + invCandidate2->condition = binaryNode->arg1; + return invCandidate2; + } return NULL; } Modified: firebird/trunk/src/jrd/Optimizer.h =================================================================== --- firebird/trunk/src/jrd/Optimizer.h 2011-02-07 14:32:21 UTC (rev 52313) +++ firebird/trunk/src/jrd/Optimizer.h 2011-02-07 17:54:24 UTC (rev 52314) @@ -141,6 +141,7 @@ int indexes; int dependencies; BoolExprNode* boolean; + BoolExprNode* condition; InversionNode* inversion; IndexScratch* scratch; bool used; Modified: firebird/trunk/src/jrd/opt.cpp =================================================================== --- firebird/trunk/src/jrd/opt.cpp 2011-02-07 14:32:21 UTC (rev 52313) +++ firebird/trunk/src/jrd/opt.cpp 2011-02-07 17:54:24 UTC (rev 52314) @@ -166,7 +166,7 @@ bool isComputable(CompilerScratch* csb) const { - return m_node ? m_node->computable(csb, -1, false, false, NULL) : true; + return m_node ? m_node->computable(csb, -1, false, false) : true; } protected: @@ -2193,8 +2193,8 @@ (inner_flag ? opt->opt_base_missing_conjuncts : opt->opt_conjuncts.getCount()); RecordSource* rsb = NULL; - IndexTableScan* nav_rsb = NULL; InversionNode* inversion = NULL; + BoolExprNode* condition = NULL; if (relation->rel_file) { @@ -2216,12 +2216,26 @@ else { // Persistent table + IndexTableScan* nav_rsb = NULL; OptimizerRetrieval optimizerRetrieval(*tdbb->getDefaultPool(), opt, stream, outer_flag, inner_flag, sort_ptr); AutoPtr<InversionCandidate> candidate(optimizerRetrieval.getInversion(&nav_rsb)); - if (candidate && candidate->inversion) + if (candidate) + { inversion = candidate->inversion; + condition = candidate->condition; + } + + if (nav_rsb) + { + if (inversion && !condition) + { + nav_rsb->setInversion(inversion); + } + + rsb = nav_rsb; + } } if (outer_flag) @@ -2278,17 +2292,22 @@ } } - if (nav_rsb) - { - nav_rsb->setInversion(inversion); - fb_assert(!rsb); - rsb = nav_rsb; - } - if (!rsb) { if (inversion) + { rsb = FB_NEW(*tdbb->getDefaultPool()) BitmapTableScan(csb, alias, stream, inversion); + + if (condition && + condition->computable(csb, -1, false, false) && + !condition->jrdStreamFinder(csb, stream)) + { + RecordSource* const other_rsb = + FB_NEW(*tdbb->getDefaultPool()) FullTableScan(csb, alias, stream); + + rsb = FB_NEW(*tdbb->getDefaultPool()) ConditionalStream(csb, other_rsb, rsb, condition); + } + } else { rsb = FB_NEW(*tdbb->getDefaultPool()) FullTableScan(csb, alias, stream); Added: firebird/trunk/src/jrd/recsrc/ConditionalStream.cpp =================================================================== --- firebird/trunk/src/jrd/recsrc/ConditionalStream.cpp (rev 0) +++ firebird/trunk/src/jrd/recsrc/ConditionalStream.cpp 2011-02-07 17:54:24 UTC (rev 52314) @@ -0,0 +1,171 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. + * + * Software distributed under the License is distributed AS IS, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. + * See the License for the specific language governing rights + * and limitations under the License. + * + * The Original Code was created by Dmitry Yemanov + * for the Firebird Open Source RDBMS project. + * + * Copyright (c) 2011 Dmitry Yemanov <di...@fi...> + * and all contributors signed below. + * + * All Rights Reserved. + * Contributor(s): ______________________________________. + */ + +#include "firebird.h" +#include "../common/common.h" +#include "../jrd/jrd.h" +#include "../jrd/req.h" +#include "../dsql/BoolNodes.h" +#include "../jrd/cmp_proto.h" +#include "../jrd/evl_proto.h" +#include "../jrd/mov_proto.h" +#include "../jrd/evl_proto.h" + +#include "RecordSource.h" + +using namespace Firebird; +using namespace Jrd; + +// ------------------------------------ +// Data access: predicate driven filter +// ------------------------------------ + +ConditionalStream::ConditionalStream(CompilerScratch* csb, + RecordSource* first, RecordSource* second, + BoolExprNode* boolean) + : m_first(first), m_second(second), m_boolean(boolean) +{ + fb_assert(m_first && m_second && m_boolean); + + m_impure = CMP_impure(csb, sizeof(Impure)); +} + +void ConditionalStream::open(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + Impure* const impure = request->getImpure<Impure>(m_impure); + + impure->irsb_flags = irsb_open; + + impure->irsb_next = m_boolean->execute(tdbb, request) ? m_first : m_second; + impure->irsb_next->open(tdbb); +} + +void ConditionalStream::close(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + + invalidateRecords(request); + + Impure* const impure = request->getImpure<Impure>(m_impure); + + if (impure->irsb_flags & irsb_open) + { + impure->irsb_flags &= ~irsb_open; + + impure->irsb_next->close(tdbb); + } +} + +bool ConditionalStream::getRecord(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + Impure* const impure = request->getImpure<Impure>(m_impure); + + if (!(impure->irsb_flags & irsb_open)) + { + return false; + } + + return impure->irsb_next->getRecord(tdbb); +} + +bool ConditionalStream::refetchRecord(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + Impure* const impure = request->getImpure<Impure>(m_impure); + return impure->irsb_next->refetchRecord(tdbb); +} + +bool ConditionalStream::lockRecord(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + Impure* const impure = request->getImpure<Impure>(m_impure); + return impure->irsb_next->lockRecord(tdbb); +} + +void ConditionalStream::print(thread_db* tdbb, string& plan, bool detailed, unsigned level) const +{ + if (detailed) + { + plan += printIndent(++level) + "Condition"; + m_first->print(tdbb, plan, true, level); + m_second->print(tdbb, plan, true, level); + } + else + { + if (!level) + { + plan += "("; + } + + m_first->print(tdbb, plan, false, level + 1); + + plan += ", "; + + m_second->print(tdbb, plan, false, level + 1); + + if (!level) + { + plan += ")"; + } + } +} + +void ConditionalStream::markRecursive() +{ + m_first->markRecursive(); + m_second->markRecursive(); +} + +void ConditionalStream::findUsedStreams(StreamsArray& streams) const +{ + m_first->findUsedStreams(streams); + m_second->findUsedStreams(streams); +} + +void ConditionalStream::invalidateRecords(jrd_req* request) const +{ + Impure* const impure = request->getImpure<Impure>(m_impure); + impure->irsb_next->invalidateRecords(request); +} + +void ConditionalStream::nullRecords(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + Impure* const impure = request->getImpure<Impure>(m_impure); + impure->irsb_next->nullRecords(tdbb); +} + +void ConditionalStream::saveRecords(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + Impure* const impure = request->getImpure<Impure>(m_impure); + impure->irsb_next->saveRecords(tdbb); +} + +void ConditionalStream::restoreRecords(thread_db* tdbb) const +{ + jrd_req* const request = tdbb->getRequest(); + Impure* const impure = request->getImpure<Impure>(m_impure); + impure->irsb_next->restoreRecords(tdbb); +} Property changes on: firebird/trunk/src/jrd/recsrc/ConditionalStream.cpp ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:eol-style + native Modified: firebird/trunk/src/jrd/recsrc/RecordSource.h =================================================================== --- firebird/trunk/src/jrd/recsrc/RecordSource.h 2011-02-07 14:32:21 UTC (rev 52313) +++ firebird/trunk/src/jrd/recsrc/RecordSource.h 2011-02-07 17:54:24 UTC (rev 52314) @@ -996,6 +996,41 @@ size_t m_saveSize; }; + class ConditionalStream : public RecordSource + { + struct Impure : public RecordSource::Impure + { + const RecordSource* irsb_next; + }; + + public: + ConditionalStream(CompilerScratch* csb, RecordSource* first, RecordSource* second, + BoolExprNode* boolean); + + void open(thread_db* tdbb) const; + void close(thread_db* tdbb) const; + + bool getRecord(thread_db* tdbb) const; + bool refetchRecord(thread_db* tdbb) const; + bool lockRecord(thread_db* tdbb) const; + + void print(thread_db* tdbb, Firebird::string& plan, + bool detailed, unsigned level) const; + + void markRecursive(); + void invalidateRecords(jrd_req* request) const; + + void findUsedStreams(StreamsArray& streams) const; + void nullRecords(thread_db* tdbb) const; + void saveRecords(thread_db* tdbb) const; + void restoreRecords(thread_db* tdbb) const; + + private: + NestConst<RecordSource> m_first; + NestConst<RecordSource> m_second; + NestConst<BoolExprNode> const m_boolean; + }; + } // namespace #endif // JRD_RECORD_SOURCE_H This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |