|
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.
|