mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 23:23:03 +01:00
105cd42e21
Created a couple of temporary vars for code simplification.
296 lines
8.0 KiB
C++
296 lines
8.0 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/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.2;
|
|
const double REDUCE_SELECTIVITY_FACTOR_LESS = 0.5;
|
|
const double REDUCE_SELECTIVITY_FACTOR_GREATER = 0.5;
|
|
const double REDUCE_SELECTIVITY_FACTOR_STARTING = 0.01;
|
|
|
|
const double MAXIMUM_SELECTIVITY = 1.0;
|
|
|
|
// Default (Minimum) cost (nr. of pages) for an index.
|
|
const int DEFAULT_INDEX_COST = 1;
|
|
|
|
|
|
class jrd_nod;
|
|
struct index_desc;
|
|
class OptimizerBlk;
|
|
class jrd_rel;
|
|
|
|
bool OPT_computable(CompilerScratch*, jrd_nod*, SSHORT, bool, bool);
|
|
#ifdef EXPRESSION_INDICES
|
|
bool OPT_expression_equal(thread_db*, OptimizerBlk*, const index_desc*,
|
|
jrd_nod*, USHORT);
|
|
bool OPT_expression_equal2(thread_db*, OptimizerBlk*, jrd_nod*,
|
|
jrd_nod*, USHORT);
|
|
#endif
|
|
double OPT_getRelationCardinality(thread_db*, jrd_rel*, const Format*);
|
|
VaryingString* OPT_make_alias(thread_db*, const CompilerScratch*, const CompilerScratch::csb_repeat*);
|
|
jrd_nod* OPT_make_binary_node(NOD_T, jrd_nod*, jrd_nod*, bool);
|
|
USHORT OPT_nav_rsb_size(RecordSource*, USHORT, USHORT);
|
|
|
|
inline int STREAM_INDEX(const jrd_nod* node)
|
|
{
|
|
switch (node->nod_type)
|
|
{
|
|
case nod_relation:
|
|
return e_rel_stream;
|
|
case nod_procedure:
|
|
return e_prc_stream;
|
|
case nod_union:
|
|
return e_uni_stream;
|
|
default:
|
|
return e_agg_stream;
|
|
}
|
|
}
|
|
|
|
enum segmentScanType {
|
|
segmentScanNone,
|
|
segmentScanGreater,
|
|
segmentScanLess,
|
|
segmentScanBetween,
|
|
segmentScanEqual,
|
|
segmentScanEquivalent,
|
|
segmentScanMissing,
|
|
segmentScanStarting
|
|
};
|
|
|
|
class IndexScratchSegment
|
|
{
|
|
public:
|
|
IndexScratchSegment(MemoryPool& p);
|
|
IndexScratchSegment(MemoryPool& p, IndexScratchSegment* segment);
|
|
|
|
jrd_nod* lowerValue; // lower bound on index value
|
|
jrd_nod* upperValue; // upper bound on index value
|
|
int scope; // highest scope level
|
|
segmentScanType scanType; // scan type
|
|
|
|
Firebird::Array<jrd_nod*> matches;
|
|
};
|
|
|
|
class IndexScratch
|
|
{
|
|
public:
|
|
IndexScratch(MemoryPool& p, thread_db* tdbb, index_desc* idx, CompilerScratch::csb_repeat* csb_tail);
|
|
IndexScratch(MemoryPool& p, 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; //
|
|
double cardinality; // Estimated cardinality when using the whole index
|
|
|
|
bool excludeLower; //
|
|
bool excludeUpper; //
|
|
|
|
Firebird::Array<IndexScratchSegment*> segments;
|
|
};
|
|
|
|
typedef Firebird::SortedArray<int> SortedStreamList;
|
|
|
|
class InversionCandidate
|
|
{
|
|
public:
|
|
InversionCandidate(MemoryPool& p);
|
|
|
|
double selectivity;
|
|
double cost;
|
|
USHORT nonFullMatchedSegments;
|
|
USHORT matchedSegments;
|
|
int indexes;
|
|
int dependencies;
|
|
jrd_nod* boolean;
|
|
jrd_nod* inversion;
|
|
IndexScratch* scratch;
|
|
bool used;
|
|
bool unique;
|
|
|
|
Firebird::Array<jrd_nod*> matches;
|
|
SortedStreamList dependentFromStreams;
|
|
};
|
|
|
|
typedef Firebird::HalfStaticArray<InversionCandidate*, 16> InversionCandidateList;
|
|
typedef Firebird::Array<IndexScratch*> IndexScratchList;
|
|
|
|
class OptimizerRetrieval
|
|
{
|
|
public:
|
|
OptimizerRetrieval(MemoryPool& p, OptimizerBlk* opt, SSHORT streamNumber,
|
|
bool outer, bool inner, jrd_nod** sortNode);
|
|
~OptimizerRetrieval();
|
|
|
|
InversionCandidate* getCost();
|
|
InversionCandidate* getInversion(RecordSource** rsb);
|
|
|
|
protected:
|
|
jrd_nod* composeInversion(jrd_nod* node1, jrd_nod* node2, NOD_T node_type) const;
|
|
void findDependentFromStreams(jrd_nod* node, SortedStreamList* streamList) const;
|
|
VaryingString* getAlias();
|
|
InversionCandidate* generateInversion(RecordSource** rsb);
|
|
RecordSource* generateNavigation();
|
|
bool getInversionCandidates(InversionCandidateList* inversions,
|
|
IndexScratchList* indexScratches, USHORT scope) const;
|
|
jrd_nod* makeIndexNode(const index_desc* idx) const;
|
|
jrd_nod* makeIndexScanNode(IndexScratch* indexScratch) const;
|
|
InversionCandidate* makeInversion(InversionCandidateList* inversions, bool top = false) const;
|
|
bool matchBoolean(IndexScratch* indexScratch, jrd_nod* boolean, USHORT scope) const;
|
|
InversionCandidate* matchOnIndexes(IndexScratchList* indexScratches,
|
|
jrd_nod* boolean, USHORT scope) 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, jrd_nod* boolean, USHORT segment) const;
|
|
private:
|
|
MemoryPool& pool;
|
|
thread_db* tdbb;
|
|
SSHORT stream;
|
|
VaryingString* alias;
|
|
jrd_nod** sort;
|
|
jrd_rel* relation;
|
|
CompilerScratch* csb;
|
|
Database* database;
|
|
OptimizerBlk* optimizer;
|
|
IndexScratchList indexScratches;
|
|
InversionCandidateList inversionCandidates;
|
|
bool innerFlag;
|
|
bool outerFlag;
|
|
bool createIndexScanNodes;
|
|
bool setConjunctionsMatched;
|
|
};
|
|
|
|
class IndexRelationship
|
|
{
|
|
public:
|
|
IndexRelationship();
|
|
|
|
int stream;
|
|
bool unique;
|
|
double cost;
|
|
double cardinality;
|
|
};
|
|
|
|
typedef Firebird::Array<IndexRelationship*> IndexedRelationships;
|
|
|
|
class InnerJoinStreamInfo
|
|
{
|
|
public:
|
|
InnerJoinStreamInfo(MemoryPool& p);
|
|
bool independent() const;
|
|
|
|
int stream;
|
|
bool baseUnique;
|
|
double baseCost;
|
|
int baseIndexes;
|
|
int baseConjunctionMatches;
|
|
bool used;
|
|
|
|
IndexedRelationships indexedRelationships;
|
|
Firebird::Array<int> previousExpectedStreams;
|
|
};
|
|
|
|
typedef Firebird::HalfStaticArray<InnerJoinStreamInfo*, 8> StreamInfoList;
|
|
|
|
class OptimizerInnerJoin
|
|
{
|
|
public:
|
|
OptimizerInnerJoin(MemoryPool& p, OptimizerBlk* opt, UCHAR* streams,
|
|
RiverStack& river_stack, jrd_nod** sort_clause,
|
|
jrd_nod** project_clause, jrd_nod* plan_clause);
|
|
~OptimizerInnerJoin();
|
|
|
|
int findJoinOrder();
|
|
|
|
protected:
|
|
void calculateCardinalities();
|
|
void calculateStreamInfo();
|
|
bool cheaperRelationship(IndexRelationship* checkRelationship,
|
|
IndexRelationship* withRelationship) const;
|
|
bool estimateCost(USHORT stream, double *cost,
|
|
double *resulting_cardinality) const;
|
|
void findBestOrder(int position, InnerJoinStreamInfo* stream,
|
|
IndexedRelationships* processList, double cost, double cardinality);
|
|
void getIndexedRelationship(InnerJoinStreamInfo* baseStream,
|
|
InnerJoinStreamInfo* testStream);
|
|
InnerJoinStreamInfo* getStreamInfo(int stream);
|
|
#ifdef OPT_DEBUG
|
|
void printBestOrder() const;
|
|
void printFoundOrder(int position, double positionCost,
|
|
double positionCardinality, double cost, double cardinality) const;
|
|
void printProcessList(const IndexedRelationships* processList, int stream) const;
|
|
void printStartOrder() const;
|
|
#endif
|
|
|
|
private:
|
|
MemoryPool& pool;
|
|
thread_db* tdbb;
|
|
jrd_nod** sort;
|
|
jrd_nod** project;
|
|
jrd_nod* plan;
|
|
CompilerScratch* csb;
|
|
Database* database;
|
|
OptimizerBlk* optimizer;
|
|
StreamInfoList innerStreams;
|
|
int remainingStreams;
|
|
};
|
|
|
|
|
|
} // namespace Jrd
|
|
|
|
#endif // OPTIMIZER_H
|