Files
secondo/Optimizer/Updates/improvedcosts.pl
2026-01-23 17:03:45 +08:00

1142 lines
42 KiB
Prolog

/*
8 Computing Edge Costs for Plan Edges
This extension requires, that ~optimizerOption(determinePredSig)~ is set.
8.1 The Costs of Terms
----
Implemented:
cost(+Term, +Sel, +Pred,
?ResAttrList, -ResTupleSize, -ResCard, -Cost)
Planned:
cost(+Term, +POGnode, +Sel, +Pred,
?ResAttrList, -ResTupleSize, -ResCard, -Cost)
----
Calculates the expected ~Cost~ of an executable ~Term~ representing a
predicate ~Pred~ with selectivity ~Sel~.
The costedge starts from node ~POGnode~ within the predicate order graph.
This information can be used to retrieve and propagate information on attribute
types and sizes throughout the recursive evaluation of the cost-predicate.
While the result's tuple size is always propagated up, ~ResAttrList~ can be set to
~ignore~. In this case, the attribute list is not considered by the recursive calls.
Otherwise, ~cost/8~ returns the list of available attributes ~ResAttrList~ with all
available information on attribute names and sizes. ~ResAttrList~ has format
----
[[AttrName, AttrType, sizeTerm(MemSize, CoreSize, LOBSize)], [...]]
----
with one inner list for each attribute.
This is evaluated recursively descending into the term. When the operator
realizing a predicate (e.g. ~filter~) is encountered, the selectivity
~Sel~ is used to determine the size of the result.
If more than a single operator with a selectivity occurs within ~Term~, the
topmost call receives the total selectivity as an argument.
Information on attributes and tuple sizes for each node ~N~ of the POG
can be retrieved by calling
----
getResTupleSize(+Node, -ResCardinality)
getResAttrList(+Node, -ResAttributeList)
----
Operator-related constants used within the cost functions should be
stored in facts
---- costConst(+OpName, +ConstName, -Value)
----
Within the term,
---- optimizerAnnotation(+Plan, +Note)
----
can be used, to annotate a plan ~Plan~ with internal information ~Note~, during
plan creation and/or cost estimation.
When found within special operators, it may encode additional information.
So, it is used to pass down information into the evaluation of the sub plans.
If encountered alone, it is just ignored.
*/
/*
8.1.0 Plan Annotations
*/
% Section:Start:cost_7_b
% Section:End:cost_7_b
% ignore plan annotations:
cost(optimizerAnnotation(X,_), Sel, Pred, ResAttrList,
ResTupleSize, ResCard, 0) :-
cost(X, Sel, Pred, ResAttrList, ResTupleSize, ResCard, 0),!.
% Section:Start:cost_7_m
% Section:End:cost_7_m
/*
8.1.1 Arguments
Arguments are either basic relations, or intermediate results.
*/
% the if-then-else-part is just for error-detection --- FIXME!
cost(rel(Rel, X1_), Sel, Pred, ResAttrList, ResTupleSize, ResCard, 0) :-
dcName2internalName(RelDC,Rel),
( Rel = RelDC
-> true
; (
write('ERROR:\tcost/8 failed due to non-dc relation name.'), nl,
write('---> THIS SHOULD BE CORRECTED!'), nl,
throw(error_Internal(optimizer_cost(rel(Rel, X1_), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, 0)
:malformedExpression)),
fail
)
),
( (ground(ResAttrList), ResAttrList = ignore)
-> true ; getRelAttrList(RelDC, ResAttrList, _/*ResTupleSize*/)
),
tupleSizeSplit(RelDC,ResTupleSize),
card(Rel, ResCard),!.
cost(res(N), _, _, ResAttrList, ResTupleSize, ResCard, 0) :-
resultSize(N, ResCard),
getResTupleSize(N,ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true ; getResAttrList(N, ResAttrList)
),!.
/*
8.1.2 Operators
*/
% can handle rel and tconsume(...)
cost(feed(X), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(X, Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost1),
costConst(feed, pertuple, U),
costConst(feed, perbyte, V),
ResTupleSize = sizeTerm(_ /*MemSize*/, Core, _/*LOB*/),
Cost is Cost1
+ ResCard * ( U + Core * V ),!.
cost(feedproject(X, ProjAttrFields), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(X, Sel, Pred, ResAttrList1, _/*ResTupleSize1*/, ResCard, Cost1),
costConst(feedproject, msPerTuple, U),
costConst(feedproject, msPerByte, V),
costConst(feedproject, msPerAttr, W),
findall(AttrName,
memberchk(attr(AttrName,_,_),ProjAttrFields),
ProjAttrNames),
projectAttrList(ResAttrList1, ProjAttrNames, ResAttrList2, ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; ResAttrList = ResAttrList2
),
ResTupleSize = sizeTerm(_/*MemSize*/, Core, _/*LOB*/),
length(ProjAttrNames,NoAttrs),
Cost is Cost1
+ ResCard * ( U
+ Core * V
+ NoAttrs * W),!.
cost(consume(X),Sel, Pred, ResAttrList,
ResTupleSize, ResCard, Cost) :-
cost(X, Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost1),
costConst(consume, msPerTuple, U),
costConst(consume, msPerByteCore, V),
costConst(consume, msPerByteLOB, W),
ResTupleSize = sizeTerm(MemSize, Core, LOB),
Cost is Cost1
+ ResCard * ( U
+ V * max(MemSize, Core)
+ W * LOB),!.
cost(tconsume(X),Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(X, Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost1),
ResCard = sizeTerm(Mem,Core,Lob),
TRelSize is (max(Mem,Core) + Lob) * ResCard,
costConst(general, maxMemBytePerOperator, MaxMem),
( TRelSize > MaxMem % does not fit into in-memory-tuple-buffer
-> cost(consume(X), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost)
; Cost = Cost1
),!.
/*
For ~filter~, there are several special cases to distinguish:
1 ~filter(spatialjoin(...), P)~
2 ~filter(gettuples(...), P)~
3 ~filter(windowintersects(...), P)~
4 ``normal'' ~filter(...)~
For the first three cases, the edge is the translation of a spatial predicate,
that makes use of bounding box checks. The first argument of filter will already
reduce the set of possible candidates, so that the cardinality of tuples
processed by filter will be smaller than the cardinality passed down in the 3rd
argument of ~cost~. Also, the selectivity passed with the second argument of
~cost~ is the ~total~ selectivity. To get the selectivity of the preselection,
one can analyse the predicate and lookup the BBox-Selectivity calling
~getBBoxSel/2~ for that predicate, which should be passed to the recursive call
of ~cost~.
PROBLEM: What happens with the entropy-optimizer? As for cases 2 + 3, there is
no problem, as the index is used to create a fresh tuple stream. But, as for
case 1, we might get into problems, as the selectivity of the bbox-check depends
on earlier predicates - so we should consider both selectivities in the
minimization of the entropy.
*/
% rule for filter with pre-filtering
cost(filter(X, _), Sel, Pred, ResAttrList,
ResTupleSize, ResCard, Cost) :-
isPrefilter(X), % holds for spatialjoin or loopjoin
% the prefilter has already reduced the cardinality of candidates
selectivity(Pred, _, BBoxSel, CalcPET, ExpPET),
( BBoxSel > 0
-> RefinementSel is Sel/BBoxSel
; RefinementSel is 1 % if BBoxSel = 0 then ResCard1 is also 0
),
cost(X, BBoxSel, Pred, ResAttrList, ResTupleSize, ResCard1, Cost1),
costConst(filter, msPerTuple, U), % ms per tuple
ResCard is ResCard1 * RefinementSel,
Cost is Cost1
+ ResCard1 * (U + max(CalcPET,ExpPET)),!.
% rule for filter with spatio-temporal pattern
cost(filter(gettuples(rdup(sort(windowintersectsS(dbobject(IndexName), BBox))),
rel(RelName, _)), FilterPred), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
dm(costFunctions,['cost(filter(gettuples(rdup(sort(windowintersectsS(...): ',
'IndexName= ',IndexName,', BBox=',BBox,
', FilterPred=',FilterPred]),
dcName2internalName(RelDC,RelName),
( RelName = RelDC
-> true
; (
write('ERROR:\tcost/8 failed due to non-dc relation name.'), nl,
write('---> THIS SHOULD BE CORRECTED!'), nl,
throw(error_Internal(optimizer_cost(filter(gettuples(rdup(sort(
windowintersectsS(dbobject(IndexName), BBox))),
rel(RelName, _)), FilterPred), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost)
:malformedExpression)),
fail
)
),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; getRelAttrList(RelDC, ResAttrList, _/*ResTupleSize*/)
),
tupleSizeSplit(RelDC,ResTupleSize),
Cost is 0,
card(RelName, RelCard),
ResCard is RelCard * Sel, !.
% write('...Inside cost estimation '),nl,
% card(RelName, RelCard),
% write('...Inside cost estimation1 '),nl,
% my_concat_atom(['query no_entries(', IndexName, ') '], '', Command),
% write('...Inside cost estimation2 '- Command),nl,
% secondo(Command, [_,IndexCard]),
% write('...IndexCard' - IndexCard),nl,
% windowintersectsTC(WITC),
% write('...Inside cost estimation3 '),nl,
% CostWI is Sel * 1.2 * IndexCard * WITC * 0.25,
% including 20% false positives
% write('...Inside cost estimation4 '),nl,
% sorttidTC(STC),
% write('...Inside cost estimation5 '),nl,
% CostSort is Sel * 1.2 * IndexCard * STC,
% write('...Inside cost estimation6 '),nl,
% rdupTC(RDTC),
% write('...Inside cost estimation7 '),nl,
% CostRD is Sel * 1.2 * IndexCard * RDTC,
% write('...Inside cost estimation8 '),nl,
% CostGT is Sel * 1.2 * WITC * 0.75,
% Cost is CostWI+ CostSort + CostRD + CostGT,
% write('...Total cost is ' - Cost),nl,
% Size is Sel * RelCard,
% write('...Final size is ' - Size),nl.
% rule for standard filter
cost(filter(X, _), Sel, Pred, ResAttrList,
ResTupleSize, ResCard, Cost) :- % 'normal' filter
cost(X, Sel, Pred, ResAttrList, ResTupleSize, ResCard1, Cost1),
costConst(filter, msPerTuple, U), % ms per tuple
getPET(Pred,CalcPET,ExpPET),
ResCard is ResCard1 * Sel,
Cost is Cost1
+ ResCard1 * (U + max(CalcPET,ExpPET)),!.
cost(product(X, Y), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> (ResAttrListX = ignore, ResAttrListY = ignore) ; true
),
cost(X, Sel, Pred, ResAttrListX, ResTupleSizeX, ResCardX, CostX),
cost(Y, Sel, Pred, ResAttrListY, ResTupleSizeY, ResCardY, CostY),
costConst(general, maxMemBytePerOperator, MaxMem),
costConst(product, msPerByteRightOnBufferOverflow, U),
costConst(product, msPerByteTotalOutput, V),
ResCard is ResCardX * ResCardY,
addSizeTerms([ResTupleSizeX,ResTupleSizeY],ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; append(ResAttrListX,ResAttrListY,ResAttrList)
),
ResTupleSizeY = sizeTerm(MemSizeY,_,_),
getTotalDiskSize(ResTupleSize,TupleSizeRes),
( ResCardY * MemSizeY > MaxMem % ToDo: does not consider LOB sizes
-> ( getTotalDiskSize(ResTupleSizeY,TupleSizeY),
BufferedDataY is ResCardY * TupleSizeY
)
; BufferedDataY is 0
),
Cost is CostX + CostY
+ BufferedDataY * U
+ ResCard * TupleSizeRes * V,!.
/*
Simplistic cost estimation for loop joins.
If attribute values are assumed independent, then the selectivity
of a subquery appearing in an index join equals the overall
join selectivity. Therefore it is possible to estimate
the result size and cost of a subquery
(i.e. ~exactmatch~ and ~exactmatchfun~). As a subquery in an
index join is executed as often as a tuple from the left
input stream arrives, it is also possible to estimate the
overall index join cost.
*/
cost(exactmatchfun(_, Rel, _), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(Rel, 1, Pred, ResAttrList, ResTupleSize, ResCard1, _),
costConst(btreelookup, msPerSearch, U),
costConst(btreelookup, msPerResultTuple, V),
ResCard is ResCard1 * Sel,
Cost is U
+ V * ResCard,!.
cost(exactmatch(_, Rel, _), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost)
:-
cost(Rel, 1, Pred, ResAttrList, ResTupleSize, ResCard1, _),
costConst(btreelookup, msPerSearch, U),
costConst(btreelookup, msPerResultTuple, V),
ResCard is ResCard1 * Sel,
Cost is U
+ V * ResCard,!.
cost(exactmatchS(dbObject(Index), _KeyValue), Sel, _Pred, ResAttrList,
ResTupleSize, ResCard, Cost)
:-
dcName2externalName(DcIndexName,Index),
getIndexStatistics(DcIndexName, noentries, _DCrelName, ResCard1),
ResAttrList = [[tid, tid, sizeTerm(MemSize, MemSize, 0)]],
secDatatype(tid, MemSize, _, _, _, _),
ResTupleSize = sizeTerm(MemSize,MemSize,0),
costConst(btreelookup, msPerSearch, U),
costConst(btreelookup, msPerResultTuple, V),
ResCard is ResCard1 * Sel,
Cost is U
+ V * ResCard * 0.25 ,!. % balance is 75% cost for gettuple
cost(leftrange(_, Rel, _), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost)
:-
cost(Rel, 1, Pred, ResAttrList, ResTupleSize, ResCard1, _),
costConst(btreelookup, msPerSearch, U),
costConst(btreelookup, msPerResultTuple, V),
ResCard is ResCard1 * Sel,
Cost is U
+ V * ResCard,!.
cost(leftrangeS(dbObject(Index), _KeyValue), Sel, _Pred, ResAttrList,
ResTupleSize, ResCard, Cost)
:-
dcName2externalName(DcIndexName,Index),
getIndexStatistics(DcIndexName, noentries, _DCrelName, ResCard1),
ResAttrList = [[tid, tid, sizeTerm(MemSize, MemSize, 0)]],
secDatatype(tid, MemSize, _, _, _, _),
ResTupleSize = sizeTerm(MemSize,MemSize,0),
costConst(btreelookup, msPerSearch, U),
costConst(btreelookup, msPerResultTuple, V),
ResCard is ResCard1 * Sel,
Cost is U
+ V * ResCard * 0.25 ,!. % balance is 75% cost for gettuple
cost(rightrange(_, Rel, _), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost)
:-
cost(Rel, 1, Pred, ResAttrList, ResTupleSize, ResCard1, _),
costConst(btreelookup, msPerSearch, U),
costConst(btreelookup, msPerResultTuple, V),
ResCard is ResCard1 * Sel,
Cost is U
+ V * ResCard,!.
cost(rightrangeS(dbObject(Index), _KeyValue), Sel, _Pred, ResAttrList,
ResTupleSize, ResCard, Cost)
:-
dcName2externalName(DcIndexName,Index),
getIndexStatistics(DcIndexName, noentries, _DCrelName, ResCard1),
ResAttrList = [[tid, tid, sizeTerm(MemSize, MemSize, 0)]],
secDatatype(tid, MemSize, _, _, _, _),
ResTupleSize = sizeTerm(MemSize,MemSize,0),
costConst(btreelookup, msPerSearch, U),
costConst(btreelookup, msPerResultTuple, V),
ResCard is ResCard1 * Sel,
Cost is U
+ V * ResCard * 0.25 ,!. % balance is 75% cost for gettuple
cost(range(_, Rel, _), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(Rel, 1, Pred, ResAttrList, ResTupleSize, ResCard1, _),
costConst(btreelookup, msPerSearch, U),
costConst(btreelookup, msPerResultTuple, V),
ResCard is ResCard1 * Sel,
Cost is U
+ V * ResCard,!.
cost(rangeS(dbObject(Index), _KeyValue), Sel, _Pred, ResAttrList,
ResTupleSize, ResCard, Cost)
:-
dcName2externalName(DcIndexName,Index),
getIndexStatistics(DcIndexName, noentries, _DCrelName, ResCard1),
ResAttrList = [[tid, tid, sizeTerm(MemSize, MemSize, 0)]],
secDatatype(tid, MemSize, _, _, _, _),
ResTupleSize = sizeTerm(MemSize,MemSize,0),
costConst(btreelookup, msPerSearch, U),
costConst(btreelookup, msPerResultTuple, V),
ResCard is ResCard1 * Sel,
Cost is U
+ V * ResCard * 0.25 ,!. % balance is 75% cost for gettuple
cost(loopjoin(X, Y), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> (ResAttrListX = ignore, ResAttrListY = ignore) ; true
),
cost(X, 1, Pred, ResAttrListX, ResTupleSizeX, ResCardX, CostX),
cost(Y, Sel, Pred, ResAttrListY, ResTupleSizeY, ResCardY, CostY),
addSizeTerms([ResTupleSizeX,ResTupleSizeY],ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; append(ResAttrListX,ResAttrListY,ResAttrList)
),
ResCard is ResCardX * ResCardY,
Cost is CostX + ResCardX * CostY,!.
cost(loopsel(X, Y), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(X, 1, Pred, ignore, _, ResCardX, CostX),
cost(Y, Sel, Pred, ResAttrList, ResTupleSize, ResCardY, CostY),
ResCard is ResCardX * ResCardY,
Cost is CostX + ResCardX * CostY,!.
cost(fun(_, X), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(X, Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost),!.
cost(hashjoin(X, Y, _, _, _ /* NBuckets */), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> (ResAttrListX = ignore, ResAttrListY = ignore) ; true
),
cost(X, Sel, Pred, ResAttrListX, ResTupleSizeX, ResCardX, CostX),
cost(Y, Sel, Pred, ResAttrListY, ResTupleSizeY, ResCardY, CostY),
addSizeTerms([ResTupleSizeX,ResTupleSizeY],ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; append(ResAttrListX,ResAttrListY,ResAttrList)
),
ResCard is ResCardX * ResCardY * Sel,
costConst(general, maxMemBytePerOperator, MaxMem),
costConst(hashjoin, msPerProbeTuple, U),
costConst(hashjoin, msPerRightTuple, V),
costConst(hashjoin, msPerResultTuple, W),
costConst(hashjoin, byteBufferSizeRatioY, R),
ResTupleSizeY = sizeTerm(MemSizeY,_,_),
MemorySecond is MaxMem * R,
NoPasses is 1 + ((ResCardY * MemSizeY) / MemorySecond),
Cost is CostX + CostY
+ ResCardY * V % reading into hashtable
+ ResCardX * NoPasses * U % probing
+ ResCard * W,!. % output tuples
cost(sort(X), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(X, Sel, Pred, ResAttrList, ResTupleSize, ResCard, CostX),
costConst(general, maxMemBytePerOperator, MaxMem),
costConst(sortby, msPerByteInputSorted, U),
costConst(sortby, msPerByteOutput, V),
costConst(sortby, msPerByteWrittenToDisk, O),
ResTupleSize = sizeTerm(Mem,Core,Lob),
Size is max(Core + Lob, Mem),
( (MaxMem / Mem) < ResCard
-> State is 0
; State is 1
),
Cost is CostX
+ ResCard * Size * (U + O * State)
+ ResCard * Size * V,!.
% Sortby with empty sorting list is ignored:
cost(sortby(X, []), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(X, Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost),!.
cost(sortby(X, Y), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
Y \= [],
cost(sort(X), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost),!.
cost(mergejoin(X, Y, _, _), Sel, Pred, ResAttrList,
ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> (ResAttrListX = ignore, ResAttrListY = ignore) ; true
),
cost(X, 1, Pred, ResAttrListX, ResTupleSizeX, ResCardX, CostX),
cost(Y, 1, Pred, ResAttrListY, ResTupleSizeY, ResCardY, CostY),
addSizeTerms([ResTupleSizeX,ResTupleSizeY],ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; append(ResAttrListX,ResAttrListY,ResAttrList)
),
ResCard is ResCardX * ResCardY * Sel,
costConst(mergejoin, msPerTupleRead, U),
costConst(mergejoin, msPerResultTuple, FX),
costConst(mergejoin, msPerResultAttribute, FY),
length(ResAttrList,NoAttrs),
Cost is CostX + CostY
+ (ResCardX + ResCardY) * (ResCardX + ResCardY) * U
+ ResCard * (FX + NoAttrs * FY),!.
cost(sortmergejoin(X, Y, _/*AX*/, _/*AY*/), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> (ResAttrListX = ignore, ResAttrListY = ignore) ; true
),
cost(X, 1, Pred, ResAttrListX, ResTupleSizeX, ResCardX, CostX),
cost(Y, 1, Pred, ResAttrListY, ResTupleSizeY, ResCardY, CostY),
addSizeTerms([ResTupleSizeX,ResTupleSizeY],ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; append(ResAttrListX,ResAttrListY,ResAttrList)
),
ResCard is ResCardX * ResCardY * Sel,
costConst(sortmergejoin, msPerByteReadSort, USortBy),
costConst(mergejoin, msPerResultTuple, XMergeJoin),
costConst(mergejoin, msPerResultAttribute, YMergeJoin),
costConst(sortmergejoin, msPerByteReadMerge, WMergeJoin),
length(ResAttrList,NoAttrs),
ResTupleSizeX = sizeTerm(MemX,CoreX,LobX),
ResTupleSizeY = sizeTerm(MemY,CoreY,LobY),
SizeX is max(CoreX + LobX,MemX),
SizeY is max(CoreY + LobY,MemY),
Cost is CostX + CostY
+ ResCardX * SizeX * USortBy
+ ResCardY * SizeY * USortBy
+ (ResCardX * SizeX + ResCardY * SizeY) * WMergeJoin
+ ResCard * (XMergeJoin + NoAttrs * YMergeJoin),!.
% two rules used by the 'interesting orders extension':
cost(sortLeftThenMergejoin(X, Y, AX, AY), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(mergejoin(sortby(X, [AX]), Y, AX, AY), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost),!.
cost(sortRightThenMergejoin(X, Y, AX, AY), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(mergejoin(X, sortby(Y, [AY]), AX, AY), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost),!.
cost(symmjoin(X, Y, _), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> (ResAttrListX = ignore, ResAttrListY = ignore) ; true
),
cost(X, 1, Pred, ResAttrListX, ResTupleSizeX, ResCardX, CostX),
cost(Y, 1, Pred, ResAttrListY, ResTupleSizeY, ResCardY, CostY),
costConst(symmjoin, msPerTuplePair, U),
addSizeTerms([ResTupleSizeX,ResTupleSizeY],ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; append(ResAttrListX,ResAttrListY,ResAttrList)
),
ResCard is ResCardX * ResCardY * Sel,
getPET(Pred, _, ExpPET), % only uses experimental PET
Cost is CostX + CostY
+ ResCardX * ResCardY * (ExpPET + U),!.
cost(spatialjoin(X, Y, _, _), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> (ResAttrListX = ignore, ResAttrListY = ignore) ; true
),
cost(X, 1, Pred, ResAttrListX, ResTupleSizeX, ResCardX, CostX),
cost(Y, 1, Pred, ResAttrListY, ResTupleSizeY, ResCardY, CostY),
spatialjoinTC(A, B), % TODO: constants needed!
addSizeTerms([ResTupleSizeX,ResTupleSizeY],ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; append(ResAttrListX,ResAttrListY,ResAttrList)
),
ResCard is ResCardX * ResCardY * Sel,
Cost is CostX + CostY % effort is essentially proportional to
+ A * (ResCardX + ResCardY) % the sizes of argument streams
+ B * ResCard,!. % cost to produce result tuples
/*
costs for pjoin2 will only be used if option ~adpativeJoin~ is enabled.
*/
cost(pjoin2(X, Y, [ _ | _ ]), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(sortmergejoin(X, Y, _, _), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost1),
cost(hashjoin(X, Y, _, _, 99997), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost2),
Cost is min(Cost1, Cost2),!.
cost(pjoin2_hj(X, Y, [ _ | _ ]), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(hashjoin(X, Y, _, _, 99997), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost),!.
cost(pjoin2_smj(X, Y, [ _ | _ ]), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(sortmergejoin(X, Y, _, _), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost),!.
cost(extend(X, ExtendFields), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> ResAttrList1 = ignore ; true
),
cost(X, Sel, Pred, ResAttrList1, ResTupleSize1, ResCard, Cost1),
costConst(extend, msPerTuple, U),
costConst(extend, msPerTupleAndAttribute, V),
( Pred = pr(_,RelArg1)
-> RelInfoList = [(1,RelArg1)]
; (Pred = pr(_,RelArg1,RelArg2), RelInfoList = [(1,RelArg1),(2,RelArg2)])
),
createExtendAttrList(ExtendFields,RelInfoList,ExtendAttrs,ExtendAttrSize),
addSizeTerms([ResTupleSize1, ExtendAttrSize],ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; append(ResAttrList1,ExtendAttrs,ResAttrList)
),
length(ExtendFields,NoNewAttrs),
Cost is Cost1
+ ResCard * (U + NoNewAttrs * V),
dm(costFunctions,['*****************************************************\n']),
dm(costFunctions,['Extended Attributes: ',ExtendAttrs,'\n']),
dm(costFunctions,['*****************************************************\n']),
!.
cost(remove(X, DropListFields), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> ResAttrList1 = ignore ; true
),
cost(X, Sel, Pred, ResAttrList1, ResTupleSize1, ResCard, Cost1),
costConst(project, msPerTuple, U),
costConst(project, msPerTupleAndAttr, V),
findall(AttrName,
( member([AttrName, _, _],ResAttrList1),
not(memberchk(attr(AttrName,_,_),DropListFields))
),
ProjAttrNames),
( (ground(ResAttrList), ResAttrList = ignore)
-> ( ResTupleSize = ResTupleSize1, %% ToDo: Fixme
NoAttrs is 3 %% ToDo: Fixme
)
; ( projectAttrList(ResAttrList1, ProjAttrNames,
ResAttrList, ResTupleSize),
length(ResAttrList,NoAttrs)
)
),
length(ResAttrList,NoAttrs),
Cost is Cost1
+ ResCard * ( U + NoAttrs * V ),!.
cost(project(X,ProjAttrFields), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> ResAttrList1 = ignore ; true
),
cost(X, Sel, Pred, ResAttrList1, ResTupleSize1, ResCard, Cost1),
costConst(project, msPerTuple, U),
costConst(project, msPerTupleAndAttr, V),
findall(AttrName,
memberchk(attr(AttrName,_,_),ProjAttrFields),
ProjAttrNames),
( (ground(ResAttrList), ResAttrList = ignore)
-> ResTupleSize = ResTupleSize1 %% ToDo: Fixme
; projectAttrList(ResAttrList1, ProjAttrNames, ResAttrList, ResTupleSize)
),
length(ProjAttrNames,NoAttrs),
Cost is Cost1
+ ResCard * ( U + NoAttrs * V ),!.
cost(projectextend(X,ProjAttrFields,ExtendFields), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> ResAttrList1 = ignore ; true
),
cost(X, Sel, Pred, ResAttrList1, ResTupleSize1, ResCard, Cost1),
costConst(project, msPerTuple, U),
costConst(project, msPerTupleAndAttr, VP),
costConst(extend, msPerTupleAndAttribute, VE),
findall(AttrName,
memberchk(attr(AttrName,_,_),ProjAttrFields),
ProjAttrNames),
projectAttrList(ResAttrList1, ProjAttrNames, ResAttrList2, ResTupleSize2),
( Pred = pr(_,RelArg1)
-> RelInfoList = [(1,RelArg1)]
; (Pred = pr(_,RelArg1,RelArg2), RelInfoList = [(1,RelArg1),(2,RelArg2)])
),
createExtendAttrList(ExtendFields,RelInfoList,ExtendAttrs,ExtendAttrSize),
addSizeTerms([ResTupleSize2, ExtendAttrSize],ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> ResTupleSize = ResTupleSize1 %% ToDo: Fixme
; append(ResAttrList2,ExtendAttrs,ResAttrList)
),
length(ProjAttrFields,NoPAttrs),
length(ExtendFields,NoEAttrs),
Cost is Cost1
+ ResCard * ( U % per tuple
+ NoEAttrs * VE % extended attrs
+ NoPAttrs * VP ), % projected attrs
dm(costFunctions,['*****************************************************\n']),
dm(costFunctions,['Extended Attributes: ',ExtendAttrs,'\n']),
dm(costFunctions,['*****************************************************\n']),
!.
%% Missing: extendstream
%% Missing: projectextendstream
%% Missing: groupby
cost(rename(X, Suffix), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> ResAttrList1 = ignore ; true
),
cost(X, Sel, Pred, ResAttrList1, ResTupleSize, ResCard, Cost),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; renameAttrs(ResAttrList1, Suffix, ResAttrList)
),!.
cost(rdup(X), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
costConst(rdup, msPerTuple, U),
costConst(rdup, msPerComparison, V),
costConst(rdup, defaultSelectivity, W),
Sel1 is Sel/W, %% claim a fraction of the overall selectivity for rdup
%% rdup filters out an relative amount of (1-W) duplicats
cost(X, Sel1, Pred, ResAttrList, ResTupleSize, ResCard1, Cost1),
ResCard is ResCard1 * W,
Cost is Cost1
+ ResCard1 * (U + V),!. %% ToDo: Cost function looks strange...
cost(krdup(X,_AttrList), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(rdup(X), Sel, Pred, ResAttrList, ResTupleSize, ResCard, Cost), !.
cost(windowintersects(dbobject(_/* Index */), Rel, _/* QueryObj */), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(Rel, Sel, Pred, ResAttrList, ResTupleSize, ResCard1, Cost1),
costConst(windowintersects, msPerTuple, U),
costConst(windowintersects, msPerByte, V),
ResTupleSize = sizeTerm(Mem,Core,Lob),
SizeE is max(Mem+Lob,Core+Lob), %% assuming Rel has only one FLOB
ResCard is ResCard1 * Sel, %% ToDo: Estimate number of results using
%% statistics on Index, Rel, and QueryObj
%% eg. Sel = Keys(Index) * area(bbox(Index))
%% / bboxArea(QueryObj) / ResCard1
Cost is Cost1 + max(ResCard,1) * (U + SizeE * V) /* * PET */,!.
% Cost function copied from windowintersects
% May be wrong, but as it is usually used together
% with 'gettuples', the total cost should be OK
cost(windowintersectsS(dbobject(IndexName), _ /* QueryObj */), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
% get relationName Rel from Index (it is not included in the arguments)
my_concat_atom([RelName|_],'_',IndexName),
dcName2internalName(RelDC,RelName),
Rel = rel(RelDC, *),
cost(Rel, Sel, Pred, ignore, _, ResCard1, Cost1),
( (ground(ResAttrList), ResAttrList = ignore)
-> true
; ( secDatatype(tid, TMem, _, _, _, _), % Xris: Error
ResAttrList = [[id, tid, sizeTerm(TMem, 0, 0)]]
)
),
costConst(windowintersects, msPerTuple, U),
costConst(windowintersects, msPerByte, V),
ResTupleSize = sizeTerm(TMem,0,0),
SizeE is TMem, % assuming Rel has only one FLOB
ResCard is ResCard1 * Sel, %% ToDo: Estimate number of results using
%% statistics on Index, Rel, and QueryObj
%% eg. Sel = Keys(Index) * area(bbox(Index))
%% / bboxArea(QueryObj) / ResCard1
Cost is Cost1 % expected to include cost of 'windowintersectsS'
+ max(ResCard,1) * (U + SizeE * V)
* 0.25,!. % other 0.75 applied in 'gettuples'
cost(gettuples(X, Rel), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> (ResAttrList1 = ignore, ResAttrList2 = ignore) ; true
),
cost(X, Sel, Pred, ResAttrList1, ResTupleSize1, ResCard, Cost1),
cost(Rel, Sel, Pred, ResAttrList2, ResTupleSize2, _, _),
( (ground(ResAttrList), ResAttrList = ignore)
-> ( secDatatype(tid, TMem, _, _, _, _),
negateSizeTerm(sizeTerm(TMem, 0, 0),NegTidSize),
addSizeTerms([NegTidSize,ResTupleSize1,ResTupleSize2],ResTupleSize)
)
; ( delete(ResAttrList1,[_,tid,TidSize],ResAttrList1WOtid), % drop tid-attr
negateSizeTerm(TidSize,NegTidSize), % adjust size
append(ResAttrList1WOtid,ResAttrList2,ResAttrList), % concat tuples
addSizeTerms([NegTidSize,ResTupleSize1,ResTupleSize2],ResTupleSize)
)
),
ResTupleSize2 = sizeTerm(Mem,Core,Lob),
SizeE is max(0,max(Mem+Lob,Core+Lob)), % assuming Rel has only one FLOB
costConst(windowintersects, msPerTuple, U),
costConst(windowintersects, msPerByte, V),
Cost is Cost1 % expected to include cost of 'windowintersectsS'
+ ResCard * (U + SizeE * V) * 0.75,!. % other 0.25 applied
% in 'windowintersectsS'
cost(gettuples2(X, Rel, attrname(TidAttr)), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
( (ground(ResAttrList), ResAttrList = ignore)
-> (ResAttrList1 = ignore, ResAttrList2 = ignore) ; true
),
cost(X, Sel, Pred, ResAttrList1, ResTupleSize1, ResCard, Cost1),
cost(Rel, Sel, Pred, ResAttrList2, ResTupleSize2, _, _),
( (ground(ResAttrList), ResAttrList = ignore)
-> ( secDatatype(tid, TMem, _, _, _, _),
negateSizeTerm(sizeTerm(TMem, 0, 0),NegTidSize),
addSizeTerms([NegTidSize,ResTupleSize1,ResTupleSize2],ResTupleSize)
)
; ( delete(ResAttrList1,[TidAttr,tid,TidSize],
ResAttrList1WOtid), % drop tid-attr
negateSizeTerm(TidSize,NegTidSize), % adjust size
append(ResAttrList1WOtid,ResAttrList2,ResAttrList),% concat tuples
addSizeTerms([NegTidSize,ResTupleSize1,ResTupleSize2],ResTupleSize)
)
),
ResTupleSize2 = sizeTerm(Mem,Core,Lob),
SizeE is max(Mem+Lob,Core+Lob), % assuming Rel has only one FLOB
costConst(windowintersects, msPerTuple, U),
costConst(windowintersects, msPerByte, V),
Cost is Cost1 % expected to include cost of 'windowintersectsS'
+ ResCard * (U + SizeE * V) * 0.75,!. % other 0.25 applied
% in 'windowintersectsS'
/*
cost functions for distancescan queries
*/
% get the Result properties from the POG's high node
cost(pogstream, _, _, ResAttrList, ResTupleSize, ResCard, 0) :-
highNode(Node),
resultSize(Node, ResCard),
getResTupleSize(Node, ResTupleSize),
( (ground(ResAttrList), ResAttrList = ignore)
-> true ; getResAttrList(Node, ResAttrList)
).
cost(distancescan(_, Rel, _, _), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, Cost) :-
cost(Rel, Sel, Pred, ResAttrList, ResTupleSize, ResCard, C1),
distancescanTC(C),
Cost is C1 + C * ResCard * log(ResCard + 1).
cost(ksmallest(X, K), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, C) :-
cost(X, Sel,Pred, ResAttrList, ResTupleSize, ResCard, CostX),
ksmallestTC(A, B),
S is min(ResCard, K),
C is CostX +
A * ResCard +
B * S * log(S + 1).
cost(createtmpbtree(rel(Rel, _), _), _, _, ResAttrList, ResTupleSize, ResCard,
Cost) :-
dcName2internalName(RelDC,Rel),
( Rel = RelDC
-> true
; (
write('ERROR:\tcost/8 failed due to non-dc relation name.'), nl,
write('---> THIS SHOULD BE CORRECTED!'), nl,
throw(error_Internal(optimizer_cost(createtmpbtree(Rel, _), _, _,
ResAttrList, ResTupleSize, ResCard, 0)
:malformedExpression)),
fail
)
),
( (ground(ResAttrList), ResAttrList = ignore)
-> true ; getRelAttrList(RelDC, ResAttrList, _/*ResTupleSize*/)
),
tupleSizeSplit(RelDC,ResTupleSize),
card(Rel, ResCard),
createbtreeTC(C),
Cost is C * ResCard * log(ResCard).
% predinfo inflicts no cost, it only annotates estimated selectivity and PET
% for progress estimation by the Secondo kernel
cost(predinfo(X, _piSel, _piPET), Sel, Pred,
ResAttrList, ResTupleSize, ResCard, C) :-
cost(X,Sel, Pred, ResAttrList, ResTupleSize, ResCard, C), !.
% Failed to compute the cost -- throw an exception!
cost(T, S, P, A, TS, RC, Cost) :-
my_concat_atom(['Calculation of cost failed.'],'',ErrMsg),
write(ErrMsg), nl,
throw(error_Internal(improvedcosts_cost(T, S, P, A, TS, RC, Cost)
::unknownError::ErrMsg)),
!, fail.
/*
The following code fragment may be needed, when also the non-conjunctive
part of the query will be assigned with costs. At the moment, it is obsolete
and therefore commented out:
----
% Dummy-Costs for simple aggregation queries
cost(simpleAggrNoGroupby(_, Stream, _), S, P, A, TS, RC, Cost) :-
cost(Stream, S, P, A, TS, RC, Cost).
cost(simpleUserAggrNoGroupby(Stream, _, _, _), S, P, A, TS, RC, Cost) :-
cost(Stream, S, P, A, TS, RC, Cost).
----
*/
% Section:Start:cost_7_e
% Section:End:cost_7_e
/*
8.2 Predicates Auxiliar to cost/8
*/
% Succeeds, if ~X~ is a term that could act as a prefilter
% --- isPrefilter(+X)
% Section:Start:isPrefilter_1_b
% Section:End:isPrefilter_1_b
isPrefilter(X) :-
X = spatialjoin(_, _, _, _),!.
isPrefilter(X) :-
X = loopjoin(_, _),!.
% Section:Start:isPrefilter_1_e
% Section:End:isPrefilter_1_e
% Reflect modifications done by the ~rename~ operator to an attribute list
% (i.e. a common ~Suffix~ is appended to every attribute name
% --- renameAttrs(+AttrList, +Suffix, -RenamedAttrList)
renameAttrs([],_,[]).
renameAttrs([[Attr, T, S]|More], Suffix, [[AttrRenamed, T, S]|MoreRes]) :-
my_concat_atom([Attr, Suffix],'_',AttrRenamed),
renameAttrs(More,Suffix,MoreRes), !.
:- dynamic(nodeAttributeList/2).
/*
---- setNodeResAttrList(+Node, +AttrList)
----
Annotate a node of the POG with a list of available attribute list ~AttrList~.
*/
% setNodeResAttrList(+Node, +AttrList)
setNodeResAttrList(Node, _) :- nodeAttributeList(Node, _), !.
setNodeResAttrList(Node, AttrList) :-
ground(Node), ground(AttrList),
assert(nodeAttributeList(Node, AttrList)),!.
setNodeResAttrList(N, A) :-
my_concat_atom(['Error in setNodeResAttrList: Unbound variable.'],'',ErrMsg),
write(ErrMsg), nl,
throw(error_Internal(improvedcosts_setNodeResAttrList(N,A)
::malformedExpression::ErrMsg)),
!, fail.
/*
----
getResAttrList(+Node, -AttrList)
getResTupleSize(+Node, -TupleSize)
----
Retrieve tuple sizes and attributes at given nodes.
*/
% getResAttrList(+Node, -AttrList)
getResAttrList(0,[]) :- !.
getResAttrList(Node,AttrList) :- nodeAttributeList(Node, AttrList), !.
% getResTupleSize(+Node, -TupleSize)
getResTupleSize(0,sizeTerm(0,0,0)) :- !.
getResTupleSize(Node, TupleSize) :- nodeTupleSize(Node, TupleSize), !.
/*
---- getSignature([+Op,+Args,+ResultType], -Op, -ArgTypeList) :-
----
Extract the operator name and the list of argument types of a ~TypeTree~
expression. If the signature cannot be retrieved, ~typeerror~ is returned
instead of the argument type list.
The input parameters [~Op~, ~Args~, ~ResultType~] can be computed for an
expression ~Expr~ and a list of relation descriptors ~RelList~ by calling
---- getSignature(+Expr,+RelList,-TypeTree)
----
~TypeTree~ then has the required format [~Op~, ~Args~, ~ResultType~].
*/
getSignature([Op,Args,_], Op, ArgTypeList) :-
findall(T,(member([_,_,T],Args)),ArgTypeList),!.
getSignature([Op,_,_],Op,typeerror).
getSignature(A,B,C) :-
throw(error_Internal(improvedcosts_getSignature(A,B,C)
:wrongInstantiationPattern)),
!, fail.
/*
8.3 Applying Cost Estination and Annotation of Intermediate Results
---- costterm(+Term, +Source, +Target, +Result, +Sel, +Pred, -Card, -Cost)
----
Determine the assessed costs of an input term using rules ~cost/8~.
~Term~ is the term, whose cost is to estimate,
~Source~ and ~Target~ are the pog node numbers incident to the edge represented by ~Term~,
~Result~ is the result number used for the result of the edge,
~Sel~ is the overall edge selectivity,
~Pred~ is the predicate represented by the edge,
~Card~ is the expected cardinality at the ~Target~ node,
~Cost~ is the expected cost in milliseconds.
*/
% costterm(+Term, +Source, +Target, +Result, +Sel, +Pred, -Card, -Cost)
costterm(Term, Source, Target, Result, Sel, Pred, Card, Cost) :-
( optimizerOption(improvedcosts)
-> ( cost(Term, Sel, Pred, ResAttrList, TupleSize, Card, Cost),
setNodeResAttrList(Result, ResAttrList),
setNodeTupleSize(Result, TupleSize)
)
; throw(error_Internal(improvedcosts_costterm(Term, Source, Target, Result,
Sel, Pred, Card,
Cost):should_not_be_called_without_option_improvedcosts))
),
!.
/*
8.4 Operator-related Constants
Operator-related constants used within the cost functions should be
stored in facts
---- costConst(+OpName, +ConstName, -Value)
----
*/
% Section:Start:costConst_3_b
% Section:End:costConst_3_b
costConst(general, maxMemBytePerOperator, 4194304). % 4 MB buffers per operator
costConst(feed, pertuple, 0.00194).
costConst(feed, perbyte, 0.0000196).
costConst(feedproject, msPerTuple, 0.002).
costConst(feedproject, msPerByte, 0.000036).
costConst(feedproject, msPerAttr, 0.0018).
costConst(consume, msPerTuple, 0.024).
costConst(consume, msPerByteCore, 0.0003).
costConst(consume, msPerByteLOB, 0.001338).
costConst(project, msPerTuple, 0.00073).
costConst(project, msPerTupleAndAttr, 0.0004).
costConst(filter, msPerTuple, 0.01).
costConst(product, msPerByteRightOnBufferOverflow, 0.0003).
costConst(product, msPerByteTotalOutput, 0.000042).
costConst(btreelookup, msPerSearch, 0.15).
costConst(btreelookup, msPerResultTuple, 0.018).
costConst(hashjoin, msPerProbeTuple, 0.023).
costConst(hashjoin, msPerRightTuple, 0.0067).
costConst(hashjoin, msPerResultTuple, 0.0025).
costConst(hashjoin, byteBufferSizeRatioY, 0.75).
costConst(sortby, msPerByteInputSorted, 0.000396).
costConst(sortby, msPerByteOutput, 0.000194).
costConst(sortby, msPerByteWrittenToDisk, 0.00004).
costConst(mergejoin, msPerTupleRead, 0.0008077).
costConst(mergejoin, msPerResultTuple, 0.0012058).
costConst(mergejoin, msPerResultAttribute, 0.0001072).
costConst(sortmergejoin, msPerByteReadMerge, 0.0001738).
costConst(sortmergejoin, msPerByteReadSort, 0.00043).
costConst(symmjoin, msPerTuplePair, 0.2).
costConst(extend, msPerTuple, 0.0012).
costConst(extend, msPerTupleAndAttribute, 0.00085).
costConst(rdup, msPerTuple, 0.01).
costConst(rdup, msPerComparison, 0.1).
costConst(rdup, defaultSelectivity, 0.9).
costConst(windowintersects, msPerTuple, 0.00194).
costConst(windowintersects, msPerByte, 0.0000106).
% Section:Start:costConst_3_e
% Section:End:costConst_3_e
/*
End of file ~improvedcosts.pl~
*/