8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-27 18:03:04 +01:00
firebird-mirror/src/jrd/Optimizer.h
Adriano dos Santos Fernandes a7948792b1 Warning.
2016-04-12 14:24:07 -03:00

384 lines
10 KiB
C++

/*
* PROGRAM: Client/Server Common Code
* MODULE: Optimizer.h
* DESCRIPTION: Optimizer
*
* 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 Arno Brinkman
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2004 Arno Brinkman <firebird@abvisie.nl>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*
*
*/
#ifndef OPTIMIZER_H
#define OPTIMIZER_H
//#define OPT_DEBUG
//#define OPT_DEBUG_RETRIEVAL
//#ifdef OPT_DEBUG
#define OPTIMIZER_DEBUG_FILE "opt_debug.out"
//#endif
#include "../common/classes/alloc.h"
#include "../common/classes/array.h"
#include "../jrd/RecordSourceNodes.h"
#include "../jrd/rse.h"
#include "../jrd/exe.h"
namespace Jrd {
// AB: 2005-11-05
// Constants below needs some discussions and ideas
const double REDUCE_SELECTIVITY_FACTOR_BETWEEN = 0.0025;
const double REDUCE_SELECTIVITY_FACTOR_LESS = 0.05;
const double REDUCE_SELECTIVITY_FACTOR_GREATER = 0.05;
const double REDUCE_SELECTIVITY_FACTOR_STARTING = 0.01;
const double REDUCE_SELECTIVITY_FACTOR_EQUALITY = 0.1;
const double REDUCE_SELECTIVITY_FACTOR_INEQUALITY = 0.3;
const double MAXIMUM_SELECTIVITY = 1.0;
const double DEFAULT_SELECTIVITY = 0.1;
const double MINIMUM_CARDINALITY = 1.0;
const double THRESHOLD_CARDINALITY = 5.0;
// Default depth of an index tree (including one leaf page),
// also representing the minimal cost of the index scan.
// We assume that the root page would be always cached,
// so it's not included here.
const int DEFAULT_INDEX_COST = 3;
struct index_desc;
class OptimizerBlk;
class jrd_rel;
class IndexTableScan;
class ComparativeBoolNode;
class InversionNode;
class PlanNode;
class SortNode;
double OPT_getRelationCardinality(thread_db*, jrd_rel*, const Format*);
Firebird::string OPT_make_alias(thread_db*, const CompilerScratch*, const CompilerScratch::csb_repeat*);
enum segmentScanType {
segmentScanNone,
segmentScanGreater,
segmentScanLess,
segmentScanBetween,
segmentScanEqual,
segmentScanEquivalent,
segmentScanMissing,
segmentScanStarting
};
class IndexScratchSegment
{
public:
explicit IndexScratchSegment(MemoryPool& p);
IndexScratchSegment(MemoryPool& p, IndexScratchSegment* segment);
ValueExprNode* lowerValue; // lower bound on index value
ValueExprNode* upperValue; // upper bound on index value
bool excludeLower; // exclude lower bound value from scan
bool excludeUpper; // exclude upper bound value from scan
int scope; // highest scope level
segmentScanType scanType; // scan type
Firebird::Array<BoolExprNode*> matches;
};
class IndexScratch
{
public:
IndexScratch(MemoryPool& p, thread_db* tdbb, index_desc* idx, CompilerScratch::csb_repeat* csb_tail);
IndexScratch(MemoryPool& p, const IndexScratch& scratch);
~IndexScratch();
index_desc* idx; // index descriptor
double selectivity; // calculated selectivity for this index
bool candidate; // used when deciding which indices to use
bool scopeCandidate; // used when making inversion based on scope
int lowerCount; //
int upperCount; //
int nonFullMatchedSegments; //
bool fuzzy; // Need to use INTL_KEY_PARTIAL in btr lookups
double cardinality; // Estimated cardinality when using the whole index
Firebird::Array<IndexScratchSegment*> segments;
};
class InversionCandidate
{
public:
explicit InversionCandidate(MemoryPool& p);
double selectivity;
double cost;
USHORT nonFullMatchedSegments;
USHORT matchedSegments;
int indexes;
int dependencies;
BoolExprNode* boolean;
BoolExprNode* condition;
InversionNode* inversion;
IndexScratch* scratch;
bool used;
bool unique;
bool navigated;
Firebird::Array<BoolExprNode*> matches;
SortedStreamList dependentFromStreams;
};
typedef Firebird::HalfStaticArray<InversionCandidate*, 16> InversionCandidateList;
typedef Firebird::ObjectsArray<IndexScratch> IndexScratchList;
class OptimizerRetrieval
{
public:
OptimizerRetrieval(MemoryPool& p, OptimizerBlk* opt, StreamType streamNumber,
bool outer, bool inner, SortNode* sortNode);
~OptimizerRetrieval();
InversionCandidate* getInversion()
{
createIndexScanNodes = true;
setConjunctionsMatched = true;
return generateInversion();
}
InversionCandidate* getCost()
{
createIndexScanNodes = false;
setConjunctionsMatched = false;
return generateInversion();
}
IndexTableScan* getNavigation();
protected:
void analyzeNavigation();
InversionNode* composeInversion(InversionNode* node1, InversionNode* node2,
InversionNode::Type node_type) const;
const Firebird::string& getAlias();
InversionCandidate* generateInversion();
void getInversionCandidates(InversionCandidateList* inversions,
IndexScratchList* indexScratches, USHORT scope) const;
InversionNode* makeIndexScanNode(IndexScratch* indexScratch) const;
InversionCandidate* makeInversion(InversionCandidateList* inversions) const;
bool matchBoolean(IndexScratch* indexScratch, BoolExprNode* boolean, USHORT scope) const;
InversionCandidate* matchDbKey(BoolExprNode* boolean) const;
InversionCandidate* matchOnIndexes(IndexScratchList* indexScratches,
BoolExprNode* boolean, USHORT scope) const;
ValueExprNode* findDbKey(ValueExprNode* dbkey, SLONG* position) const;
#ifdef OPT_DEBUG_RETRIEVAL
void printCandidate(const InversionCandidate* candidate) const;
void printCandidates(const InversionCandidateList* inversions) const;
void printFinalCandidate(const InversionCandidate* candidate) const;
#endif
bool validateStarts(IndexScratch* indexScratch, ComparativeBoolNode* cmpNode,
USHORT segment) const;
private:
MemoryPool& pool;
thread_db* tdbb;
public:
StreamType stream;
Firebird::string alias;
SortNode* sort;
jrd_rel* relation;
CompilerScratch* csb;
Database* database;
OptimizerBlk* optimizer;
IndexScratchList indexScratches;
InversionCandidateList inversionCandidates;
bool innerFlag;
bool outerFlag;
bool createIndexScanNodes;
bool setConjunctionsMatched;
IndexScratch* navigationCandidate;
};
class IndexRelationship
{
public:
IndexRelationship()
: stream(0), unique(false), cost(0), cardinality(0)
{}
StreamType stream;
bool unique;
double cost;
double cardinality;
};
typedef Firebird::Array<IndexRelationship*> IndexedRelationships;
class InnerJoinStreamInfo
{
public:
explicit InnerJoinStreamInfo(MemoryPool& p)
: indexedRelationships(p),
stream(0), baseUnique(false), baseCost(0), baseSelectivity(0),
baseIndexes(0), baseNavigated(false),
used(false), previousExpectedStreams(0)
{}
bool isIndependent() const
{
// Return true if this stream can't be used by other streams
// and it can't use index retrieval based on other streams
return (indexedRelationships.isEmpty() && !previousExpectedStreams);
}
bool isFiltered() const
{
return (baseSelectivity < MAXIMUM_SELECTIVITY);
}
IndexedRelationships indexedRelationships;
StreamType stream;
bool baseUnique;
double baseCost;
double baseSelectivity;
int baseIndexes;
bool baseNavigated;
bool used;
int previousExpectedStreams;
};
typedef Firebird::HalfStaticArray<InnerJoinStreamInfo*, 8> StreamInfoList;
class OptimizerInnerJoin
{
public:
OptimizerInnerJoin(MemoryPool& p, OptimizerBlk* opt, const StreamList& streams,
SortNode* sort_clause, PlanNode* plan_clause);
~OptimizerInnerJoin();
StreamType findJoinOrder();
protected:
void calculateStreamInfo();
bool cheaperRelationship(IndexRelationship* checkRelationship,
IndexRelationship* withRelationship) const;
void estimateCost(StreamType stream, double* cost, double* resulting_cardinality, bool start) const;
void findBestOrder(StreamType position, InnerJoinStreamInfo* stream,
IndexedRelationships* processList, double cost, double cardinality);
void getIndexedRelationship(InnerJoinStreamInfo* baseStream, InnerJoinStreamInfo* testStream);
InnerJoinStreamInfo* getStreamInfo(StreamType stream);
#ifdef OPT_DEBUG
void printBestOrder() const;
void printFoundOrder(StreamType position, double positionCost,
double positionCardinality, double cost, double cardinality) const;
void printProcessList(const IndexedRelationships* processList, StreamType stream) const;
void printStartOrder() const;
#endif
private:
MemoryPool& pool;
thread_db* tdbb;
SortNode* sort;
PlanNode* plan;
CompilerScratch* csb;
Database* database;
OptimizerBlk* optimizer;
StreamInfoList innerStreams;
StreamType remainingStreams;
};
class StreamStateHolder
{
public:
explicit StreamStateHolder(CompilerScratch* csb)
: m_csb(csb), m_streams(csb->csb_pool), m_flags(csb->csb_pool)
{
for (StreamType stream = 0; stream < csb->csb_n_stream; stream++)
m_streams.add(stream);
init();
}
StreamStateHolder(CompilerScratch* csb, const StreamList& streams)
: m_csb(csb), m_streams(csb->csb_pool), m_flags(csb->csb_pool)
{
m_streams.assign(streams);
init();
}
~StreamStateHolder()
{
for (FB_SIZE_T i = 0; i < m_streams.getCount(); i++)
{
const StreamType stream = m_streams[i];
if (m_flags[i >> 3] & (1 << (i & 7)))
m_csb->csb_rpt[stream].activate();
else
m_csb->csb_rpt[stream].deactivate();
}
}
void activate()
{
for (const StreamType* iter = m_streams.begin(); iter != m_streams.end(); ++iter)
m_csb->csb_rpt[*iter].activate();
}
void deactivate()
{
for (const StreamType* iter = m_streams.begin(); iter != m_streams.end(); ++iter)
m_csb->csb_rpt[*iter].deactivate();
}
private:
void init()
{
m_flags.resize(FLAG_BYTES(m_streams.getCount()));
for (FB_SIZE_T i = 0; i < m_streams.getCount(); i++)
{
const StreamType stream = m_streams[i];
if (m_csb->csb_rpt[stream].csb_flags & csb_active)
m_flags[i >> 3] |= (1 << (i & 7));
}
}
CompilerScratch* const m_csb;
StreamList m_streams;
Firebird::HalfStaticArray<UCHAR, sizeof(SLONG)> m_flags;
};
} // namespace Jrd
#endif // OPTIMIZER_H