3119 lines
104 KiB
Prolog
3119 lines
104 KiB
Prolog
/*
|
|
----
|
|
This file is part of SECONDO.
|
|
|
|
Copyright (C) 2004, University in Hagen, Department of Computer Science,
|
|
Database Systems for New Applications.
|
|
|
|
SECONDO is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
SECONDO is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with SECONDO; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
----
|
|
|
|
//paragraph [10] title: [{\Large \bf ] [}]
|
|
//[->] [$\rightarrow$]
|
|
//[toc] [\tableofcontents]
|
|
//[star] [$\star$]
|
|
|
|
[10] Statistics
|
|
|
|
[File ~statistics.pl~]
|
|
|
|
While module [~database.pl~] handles basic information on database objects,
|
|
like types/ schemas, tuple sizes, cardinalities etc. this module deals with
|
|
statistics on databases, that rely on predicate evaluation.
|
|
|
|
Above all, it covers the estimation of predicate selectivities, predicate
|
|
evaluation times (PETs), and type inference for expressions.
|
|
|
|
[toc]
|
|
|
|
1 Information about Selectivity of Predicates
|
|
|
|
1.1 Rules about Commutativity of Predicates
|
|
|
|
~isCommutativeOP/1~ is defined in file ``operators.pl''.
|
|
|
|
*/
|
|
|
|
% safeguards against commuting optimizer notations
|
|
commute(rel(_,_), _,_) :- !, fail.
|
|
commute(attr(_,_,_), _,_) :- !, fail.
|
|
commute(attrname(_,_,_), _,_) :- !, fail.
|
|
commute(value_expr(_,_), _,_) :- !, fail.
|
|
commute(type_expr(_), _,_) :- !, fail.
|
|
commute(dbobject(_), _,_) :- !, fail.
|
|
commute(newattr(_,_), _,_) :- !, fail.
|
|
|
|
% general rules of commution
|
|
commute(Term,_,Commuted) :-
|
|
member((Term,Commuted),[(X < Y,Y > X),(X <= Y, Y >= X),(X > Y, Y < X),
|
|
(X >= Y, Y <= X),(trcoveredby(X,Y), trcovers(Y,X))]),
|
|
!.
|
|
% special rules inferred from operator characteristics
|
|
commute(Term,ResList,Commuted) :-
|
|
optimizerOption(determinePredSig),
|
|
Term =.. [Op, Arg1, Arg2], % only binary operators may commute!
|
|
getTypeTree(Term,ResList,[_,Args,_]),
|
|
extractSignature(Args,ArgTypes), % extract argument types
|
|
checkOpProperty(Op,ArgTypes,comm), % is commutative op
|
|
Commuted =.. [Op, Arg2, Arg1], !.
|
|
% old rule - still using old ~isCommutativeOP/1~-facts
|
|
commute(Pred1, _, Pred2) :-
|
|
not(optimizerOption(determinePredSig)),
|
|
Pred1 =.. [OP, Arg1, Arg2],
|
|
( (optimizerOption(determinePredSig), checkOpProperty(Pred1,comm))
|
|
; isCommutativeOP(OP)
|
|
),
|
|
Pred2 =.. [OP, Arg2, Arg1], !.
|
|
|
|
% binary version - extracting rellist from predicate descriptor
|
|
commute(Pred1, Pred2) :-
|
|
( Pred1 = pr(_ ,A)
|
|
-> RL = [(1,A)]
|
|
; ( Pred1 = pr(_ ,A,B)
|
|
-> RL = [(1,A),(2,B)]
|
|
; fail
|
|
)
|
|
),
|
|
commute(Pred1,RL,Pred2),!.
|
|
|
|
/*
|
|
|
|
1.3 Determine the Simple Form of Predicates
|
|
|
|
Simple forms of predicates are stored in predicate ~sel~ or
|
|
in predicate ~storedSel~.
|
|
|
|
|
|
---- simple(+Term, +ArgRelList, -Simple)
|
|
----
|
|
|
|
The simple form of a term ~Term~ containing attributes of relations in
|
|
~ArgRelList~ is ~Simple~.
|
|
|
|
The ~ArgRelList~ contains elements of form:
|
|
|
|
(Index,rel(RelNameDC,Var)), where ~Index~ is the relation's index according to
|
|
its appearance in the predicate expression (1: left relation/stream, 2: right
|
|
relation/stream, 0: added attribute), ~RelNameDC~ is either the relations
|
|
DC-name or an irrel/7 term (see below), and ~Var~ is the alias name used for
|
|
the relation (or [star] if none is used).
|
|
|
|
An irrel/7 term represents an intermediate result relation and has format
|
|
~irrel(+Type, +Stream, +TOP, +Card, +SizeTerm +AttrList, +TypeSpec)~:
|
|
Such expressions are added by predicate ~nrLookupIRRel/2~. The fields' meaning
|
|
is:
|
|
|
|
* ~Type~: relation, arel, nest, unnest, query
|
|
|
|
* ~Stream~: Executable plan describing the relation
|
|
|
|
* ~TOP~: (=Transformation Operator): Operator to use if ~unnest~ or ~nest~ is
|
|
to be applied to the stream
|
|
|
|
* ~Card~: The relation's cardinality
|
|
|
|
* ~SizeTerm~ description of the relation's tuple size
|
|
|
|
* ~AttrList~: relation's attribute descriptions with enrties of form
|
|
~[DCAttr, Spelling, Case, DCFQN, Type, ArelDesc, SizeTerm]~, where ~DCAttr~
|
|
is the downcased attribute name, ~Spelling~ the correctly spelled
|
|
attribute name with downcased starting letter, ~Case~ indicates whether
|
|
the attribute name's correct starting letter is upper or lower case, ~DCFQN~
|
|
is the fully qualified DC-name of the attribute (including its relation) or
|
|
~fqn(no)~, if the attribute does not come from a relation. ~Type~ ist the
|
|
attribute's type, ~ARelDesc~ represents an AttrList if the attribute type is
|
|
arel. ~SizeTerm~ ist the attribute's size description.
|
|
|
|
* ~TypeSpec~: may provide additional information, depending on ~Type~
|
|
|
|
|
|
The predicat ~Term~ is translated into a standardized form, which is unified
|
|
with ~Simple~. Commutative predicates in ~Term~ are transformed to the
|
|
minimum equivalent expression regarding lexicographical order on the arguments,
|
|
e.g.
|
|
|
|
--- op(b,a)
|
|
---
|
|
|
|
is transformed into
|
|
|
|
--- op(a,b)
|
|
---
|
|
|
|
if ~op~ is flagged to be commutative in its operator description in file
|
|
~operators.pl~.
|
|
|
|
*/
|
|
|
|
% NVK ADDED NR
|
|
% Reflect the nested relations
|
|
|
|
% case: intermediate result relation with alias (for nested relations)
|
|
simple(attr(Attr, Index, _), RelList, rel(RelT, Var):Attr2) :-
|
|
optimizerOption(nestedRelations),
|
|
(Index=0 -> I2=1 ; I2 is Index),
|
|
memberchk((I2,rel(RelT, Var)),RelList),
|
|
RelT=..[irrel|_],
|
|
downcaseAttributeList(Attr, Attr2), !.
|
|
|
|
% case: intermediate result relation without alias (for nested relations)
|
|
simple(rel(RelT, Var), _, rel(RelT, Var)) :-
|
|
RelT=..[irrel|_].
|
|
|
|
% case: calculated attribute with alias (for nested relations)
|
|
simple(attr(Var:Attr, 0, _), RelList, Rel2:Attr2) :-
|
|
optimizerOption(nestedRelations),
|
|
memberchk((1,rel(Rel, Var)),RelList),
|
|
downcaseAttributeList(Rel,Rel2), downcaseAttributeList(Attr,Attr2), !.
|
|
|
|
% case: calculated attribute without alias (for nested relations)
|
|
simple(attr(Attr, 0, _), RelList, Rel2:Attr2) :-
|
|
optimizerOption(nestedRelations),
|
|
memberchk((1,rel(Rel, *)),RelList),
|
|
downcaseAttributeList(Rel,Rel2), downcaseAttributeList(Attr,Attr2), !.
|
|
|
|
% case: relation attribute with alias (for nested relations)
|
|
simple(attr(Var:Attr, ArgNo, _), RelList, Rel2:Attr2) :-
|
|
optimizerOption(nestedRelations),
|
|
memberchk((ArgNo,rel(Rel, Var)),RelList),
|
|
downcaseAttributeList(Rel,Rel2), downcaseAttributeList(Attr,Attr2), !.
|
|
|
|
% case: relation attribute without alias (for nested relations)
|
|
simple(attr(Attr, ArgNo, _), RelList, Rel2:Attr2) :-
|
|
optimizerOption(nestedRelations),
|
|
memberchk((ArgNo,rel(Rel, *)),RelList),
|
|
downcaseAttributeList(Rel,Rel2), downcaseAttributeList(Attr,Attr2), !.
|
|
% NVK ADDED NR END
|
|
|
|
|
|
simple(attr(Var:Attr, 0, _), RelList, Rel2:Attr2) :-
|
|
memberchk((1,rel(Rel, Var)),RelList),
|
|
downcase_atom(Rel,Rel2), downcase_atom(Attr,Attr2), !.
|
|
simple(attr(Attr, 0, _), RelList, Rel2:Attr2) :-
|
|
memberchk((1,rel(Rel, *)),RelList),
|
|
downcase_atom(Rel,Rel2), downcase_atom(Attr,Attr2), !.
|
|
simple(attr(Var:Attr, ArgNo, _), RelList, Rel2:Attr2) :-
|
|
memberchk((ArgNo,rel(Rel, Var)),RelList),
|
|
downcase_atom(Rel,Rel2), downcase_atom(Attr,Attr2), !.
|
|
simple(attr(Attr, ArgNo, _), RelList, Rel2:Attr2) :-
|
|
memberchk((ArgNo,rel(Rel, *)),RelList),
|
|
downcase_atom(Rel,Rel2), downcase_atom(Attr,Attr2), !.
|
|
simple(dbobject(X),_,dbobject(X)) :- !.
|
|
simple(value_expr(Type,Value),_,value_expr(Type,Value)) :- !.
|
|
simple(type_expr(Type),_,type_expr(Type)) :- !.
|
|
|
|
simple([], _, []) :- !.
|
|
simple([A|Rest], RelList, [Asimple|RestSimple]) :-
|
|
simple(A,RelList,Asimple),
|
|
simple(Rest,RelList,RestSimple),
|
|
!.
|
|
|
|
% Normalize simple predicates, if necessary
|
|
simple(Term,RelList,Simple) :-
|
|
compound(Term),
|
|
Term =.. [_,Arg1,Arg2],
|
|
compare(>,Arg1,Arg2),
|
|
commute(Term,RelList,Term2),
|
|
simple(Term2,RelList,Simple),
|
|
dm(selectivity,['Simple/2 - Commuting arguments: ',Term, ' changed to ',
|
|
Simple,'.\n']),
|
|
!.
|
|
|
|
simple(Term, RelList, Simple) :-
|
|
compound(Term),
|
|
Term =.. [Op|Args],
|
|
simple(Args, RelList, ArgsSimple),
|
|
Simple =..[Op|ArgsSimple],
|
|
!.
|
|
|
|
simple(Term, _, Term).
|
|
|
|
% fallback-clause for calls to old clause
|
|
% --- simple(+Term,+R1,+R2,-Simple)
|
|
simple(Term,R1,R2,Simple) :-
|
|
dm(gettypetree,['$$$$$$$ Using simple/4 fallback clause! $$$$$$$\n']),
|
|
simple(Term,[(1,R1),(2,R2)],Simple),!.
|
|
|
|
/*
|
|
|
|
---- simplePred(Pred, Simple) :-
|
|
----
|
|
|
|
The simple form of predicate ~Pred~ is ~Simple~.
|
|
|
|
*/
|
|
|
|
% handle faked predicate
|
|
simplePred(pr(fakePred(Sel,BboxSel,CalcPET,ExpPET)),
|
|
fakePred(Sel,BboxSel,CalcPET,ExpPET)) :-
|
|
( (ground(Sel), ground(BboxSel), ground(CalcPET), ground(ExpPET))
|
|
-> true
|
|
; throw(error_Internal(statistics_simplePred(
|
|
pr(fakePred(Sel,BboxSel,CalcPET,ExpPET)),
|
|
fakePred(Sel,BboxSel,CalcPET,ExpPET))
|
|
::fakePred_requires_ground_arguments))
|
|
),
|
|
!.
|
|
|
|
% old clauses used, if option ~determinePredSig~ is not set:
|
|
simplePred(pr(P, A, B), Simple) :-
|
|
not(optimizerOption(determinePredSig)),
|
|
optimizerOption(subqueries),
|
|
% (Does not work correctly:)
|
|
%simpleSubqueryPred(pr(P, A, B), Simple), % < Gueting 06-Jun-14 r 1.126
|
|
simple(P, A, B, Simple), % % > Gueting 06-Jun-14 r 1.126
|
|
!.
|
|
|
|
simplePred(pr(P, A, B), Simple) :-
|
|
not(optimizerOption(determinePredSig)),
|
|
simple(P, A, B, Simple), !.
|
|
|
|
simplePred(pr(P, A), Simple) :-
|
|
not(optimizerOption(determinePredSig)),
|
|
simple(P, A, A, Simple), !.
|
|
|
|
simplePred(X, Y) :-
|
|
not(optimizerOption(determinePredSig)),
|
|
term_to_atom(X,Xt),
|
|
my_concat_atom(['Malformed expression: \'', Xt, '\'.'],'',ErrorMsg),
|
|
throw(error_SQL(statistics_simplePred(X, Y)
|
|
::malformedExpression::ErrorMsg)),!.
|
|
|
|
|
|
% with option ~determinePredSig~ a specialized version is called:
|
|
simplePred(Pred,Simple) :-
|
|
optimizerOption(determinePredSig),
|
|
( Pred = pr(P,A,B)
|
|
-> RelList = [(1,A),(2,B)]
|
|
; ( Pred = pr(P,A)
|
|
-> RelList = [(1,A)]
|
|
; ( throw(error_Internal(statistics_simplePred(Pred, Simple)
|
|
::simplificationFailed)),
|
|
fail %% error!
|
|
)
|
|
)
|
|
),
|
|
simple(P,RelList,Simple), !.
|
|
|
|
% prompt an error, if simplification failed:
|
|
simplePred(Pred,Simple) :-
|
|
throw(error_Internal(statistics_simplePred(Pred, Simple)
|
|
::simplificationFailed)),
|
|
!, fail.
|
|
|
|
/*
|
|
|
|
1.4 Handling Selectivities, PETs and MBR Sizes
|
|
|
|
Selectivities, bounding box (MBR) intersection selectivities and average
|
|
bounding box sizes are estimated using a sample approach. The according
|
|
information is added to the knowledge base and saved to files when quitting
|
|
the optimizer.
|
|
|
|
Auxiliary predicates for ~selectivity~.
|
|
|
|
*/
|
|
|
|
sampleS(rel(Rel, Var), rel(Rel2, Var)) :-
|
|
atom_concat(Rel, '_sample_s', Rel2).
|
|
|
|
sampleJ(rel(Rel, Var), rel(Rel2, Var)) :-
|
|
atom_concat(Rel, '_sample_j', Rel2).
|
|
|
|
% create the name of a selection-sample for a relation
|
|
sampleNameS(lc(Name), lc(Sample)) :-
|
|
atom_concat(Name, '_sample_s', Sample), !.
|
|
sampleNameS(Name, Sample) :-
|
|
atom_concat(Name, '_sample_s', Sample), !.
|
|
|
|
% create the name of a join-sample for a relation
|
|
sampleNameJ(lc(Name), lc(Sample)) :-
|
|
atom_concat(Name, '_sample_j', Sample), !.
|
|
sampleNameJ(Name, Sample) :-
|
|
atom_concat(Name, '_sample_j', Sample), !.
|
|
|
|
sampleNameSmall(lc(Name), lc(Small)) :-
|
|
atom_concat(Name, '_small', Small), !.
|
|
sampleNameSmall(Name, Small) :-
|
|
atom_concat(Name, '_small', Small), !.
|
|
|
|
% NVK ADDED
|
|
feedOp(RelT, afeed) :-
|
|
RelT = rel(Term, _),
|
|
compound(Term),
|
|
Term =.. [irrel,arel|_],
|
|
!.
|
|
|
|
feedOp(_RelT, feed) :-
|
|
!.
|
|
|
|
% feedOp(RelT, afeed) :-
|
|
% RelT = rel(Term, _),
|
|
% Term =.. [irrel,arel|_], !.
|
|
%
|
|
% feedOp(RelT, feed) :-
|
|
% RelT = rel(Term, _),
|
|
% \+ Term =.. [irrel,arel|_], !.
|
|
|
|
|
|
possiblyRename(Rel, Renamed) :-
|
|
optimizerOption(nestedRelations),
|
|
Rel = rel(_, *),
|
|
!,
|
|
feedOp(Rel, Op),
|
|
Renamed =.. [Op, Rel].
|
|
|
|
possiblyRename(Rel, Renamed) :-
|
|
optimizerOption(nestedRelations),
|
|
Rel = rel(_, Name),
|
|
feedOp(Rel, Op),
|
|
Renamed1 =.. [Op, Rel],
|
|
Renamed = rename(Renamed1, Name).
|
|
|
|
% NVK ADDED END
|
|
|
|
possiblyRename(Rel, Renamed) :-
|
|
\+ optimizerOption(nestedRelations), % NVK ADDED
|
|
Rel = rel(_, *),
|
|
!,
|
|
Renamed = feed(Rel).
|
|
|
|
possiblyRename(Rel, Renamed) :-
|
|
\+ optimizerOption(nestedRelations), % NVK ADDED
|
|
Rel = rel(_, Name),
|
|
Renamed = rename(feed(Rel), Name).
|
|
|
|
dynamicPossiblyRenameJ(Rel, Renamed) :-
|
|
Rel = rel(_, *),
|
|
!,
|
|
secOptConstant(sampleJoinMaxCard, JoinSize),
|
|
secOptConstant(sampleScalingFactor, SF),
|
|
Renamed = sample(Rel, JoinSize, SF).
|
|
|
|
dynamicPossiblyRenameJ(Rel, Renamed) :-
|
|
Rel = rel(_, Name),
|
|
secOptConstant(sampleJoinMaxCard, JoinSize),
|
|
secOptConstant(sampleScalingFactor, SF),
|
|
Renamed = rename(sample(Rel, JoinSize, SF), Name).
|
|
|
|
dynamicPossiblyRenameS(Rel, Renamed) :-
|
|
Rel = rel(_, *),
|
|
!,
|
|
secOptConstant(sampleSelMaxCard, SelectionSize),
|
|
secOptConstant(sampleScalingFactor, SF),
|
|
Renamed = sample(Rel, SelectionSize, SF).
|
|
|
|
dynamicPossiblyRenameS(Rel, Renamed) :-
|
|
Rel = rel(_, Name),
|
|
secOptConstant(sampleSelMaxCard, SelectionSize),
|
|
secOptConstant(sampleScalingFactor, SF),
|
|
Renamed = rename(sample(Rel, SelectionSize, SF), Name).
|
|
|
|
|
|
/*
|
|
----
|
|
selectivityQuerySelection(+Pred, +Rel,
|
|
-QueryTime, -BBoxResCard,
|
|
-FilterResCard, -InputCard)
|
|
|
|
selectivityQueryJoin(+Pred, +Rel1, +Rel2,
|
|
-QueryTime, -BBoxResCard, -FilterInputCard,
|
|
-ResCard, -InputCard)
|
|
----
|
|
|
|
The following text needs to be revised!
|
|
|
|
The cardinality query for a selection predicate is performed on the selection
|
|
sample. The cardinality query for a join predicate is performed on the first
|
|
~n~ tuples of the selection sample vs. the join sample, where ~n~ is the size
|
|
of the join sample. It is done in this way in order to have two independent
|
|
samples for the join, avoiding correlations, especially for equality conditions.
|
|
|
|
If ~optimizerOption(dynamicSample)~ is defined, dynamic samples are used instead
|
|
of the \_sample\_j / \_sample\_s resp. \_small relations.
|
|
|
|
The predicates return the time ~QueryTime~ used for the query, and the
|
|
cardinality ~ResCard~ of the result after applying the predicate.
|
|
|
|
If ~Pred~ has a predicate operator that performs checking of overlapping minimal
|
|
bounding boxes, the selectivity query will additionally return the cardinality
|
|
after the bbox-checking in ~BBoxResCard~, otherwise its return value is set to
|
|
constant ~noBBox~.
|
|
|
|
Selectivity queries will timeout after a time specified by
|
|
~secOptConstant(sampleTimeout, Timeout)~. To calculate the selectivity, the
|
|
number of processed tuples (joines tuples) is returned as parameter ~InputCard~.
|
|
|
|
*/
|
|
|
|
/*
|
|
---- getBBoxIntersectionTerm(+Arg1,+Arg2,+Dimension,-PredTerm)
|
|
----
|
|
|
|
Return the bbox-selectivity-predicate ~PredTerm~ for ~Dimension~ dimensions
|
|
for arguments ~Arg1~ and ~Arg2~.
|
|
|
|
If ~Dimension~ is ~std~, a special operator is used, that for operands of
|
|
dimensions $n$, $m$ checks whether the bounding boxes of the objects'
|
|
projections to the first $min\{n,m\}$ dimensions interesect.
|
|
|
|
*/
|
|
|
|
% standard rule for unknown boxtypes using
|
|
% projective intersection ~bboxintersects~ (ingmar Goehr)
|
|
getBBoxIntersectionTerm(Arg1, Arg2, std, PredTerm) :-
|
|
PredTerm =.. [bboxintersects, bbox(Arg1), bbox(Arg2)], !.
|
|
|
|
% 2D-only rule:
|
|
getBBoxIntersectionTerm(Arg1,Arg2,2,PredTerm) :-
|
|
PredTerm =.. [intersects, box2d(bbox(Arg1)), box2d(bbox(Arg2))], !.
|
|
|
|
% general rule:
|
|
getBBoxIntersectionTerm(Arg1,Arg2,_,PredTerm) :-
|
|
PredTerm =.. [intersects, bbox(Arg1), bbox(Arg2)], !.
|
|
|
|
/*
|
|
|
|
----
|
|
bboxSizeQuerySel(+Term,+Rel,+TermTypeTree,-Size)
|
|
bboxSizeQueryJoin(+Term,+Rel1,+Rel2,+TermTypeTree,-Size)
|
|
----
|
|
|
|
Query for the average size (volume) of ~Term~'s MBR (in a selection or join
|
|
predicate) and store it within the knowledge base.
|
|
|
|
Only do so, if ~optimizerOption(determinePredSig)~ is active.
|
|
|
|
Returns ~Size~ = ~none~, if the term has no bounding box, or
|
|
~optimizerOption(determinePredSig)~ is not active.
|
|
|
|
*/
|
|
|
|
% For terms within selection predicates:
|
|
%--- bboxSizeQuerySel(+Term,+Rel,+TermTypeTree,-Size)
|
|
bboxSizeQuerySel(_,_,_,none) :-
|
|
not(optimizerOption(determinePredSig)),!.
|
|
|
|
bboxSizeQuerySel(Term,Rel,_,Size) :-
|
|
simple(Term, [(1,Rel)], SimpleTerm),
|
|
databaseName(DB),
|
|
storedBBoxSize(DB,SimpleTerm,Size), !. % already known
|
|
|
|
bboxSizeQuerySel(Term,Rel,[_,_,T],Size) :-
|
|
dm(selectivity,['\nbboxSizeQuerySel(',Term,', ',Rel,', [_,_,',
|
|
T,'], ',Size,') called!\n']),
|
|
( isKind(T,spatial2d) ; memberchk(T,[rect,rect3,rect4,rect8,
|
|
mpoint,upoint,ipoint,
|
|
instant,periods,
|
|
movingregion,intimeregion,uregion]) ),
|
|
simple(Term, [(1,Rel)], SimpleTerm),
|
|
Rel = rel(DCrelName, _),
|
|
( optimizerOption(dynamicSample)
|
|
-> dynamicPossiblyRenameS(Rel, RelQuery)
|
|
; ( ensureSampleSexists(DCrelName),
|
|
sampleS(Rel, RelS),
|
|
possiblyRename(RelS, RelQuery)
|
|
)
|
|
),
|
|
newVariable(NewAttr),
|
|
secOptConstant(sampleTimeout, Timeout),
|
|
SizeQueryT = avg(timeout(projectextend(RelQuery,
|
|
[],
|
|
[field(attr(NewAttr,0,l),size(bbox(Term)))]),
|
|
value_expr(real,Timeout)),
|
|
attrname(attr(NewAttr,0,l))),
|
|
plan_to_atom(SizeQueryT,SizeQueryA),
|
|
my_concat_atom(['query ',SizeQueryA],'',SizeQuery),
|
|
dm(selectivity,['\nThe Avg-Size Query is: ', SizeQuery, '\n']),
|
|
!, % no backtracking before this!
|
|
secondo(SizeQuery,[real,Size]),
|
|
dm(selectivity,['\nThe Avg-Size is: ', Size, '\n']),
|
|
databaseName(DB),
|
|
assert(storedBBoxSize(DB,SimpleTerm,Size)), !. % store it
|
|
|
|
bboxSizeQuerySel(Term,Rel,[_,_,T],none) :-
|
|
dm(selectivity,['bboxSizeQuerySel/5: Term \'',Term,'\' for relation ',Rel,
|
|
' has Type ',T,', but no bbox!\n\n']),!. % no bbox available
|
|
|
|
|
|
% For terms within join predicates:
|
|
% --- bboxSizeQueryJoin(+Term,+Rel1,+Rel2,+TermTypeTree,-Size)
|
|
bboxSizeQueryJoin(_,_,_,_,none) :-
|
|
not(optimizerOption(determinePredSig)),!.
|
|
|
|
bboxSizeQueryJoin(Term,Rel1,Rel2,_,Size) :-
|
|
simple(Term, [(1,Rel1),(2,Rel2)], SimpleTerm),
|
|
databaseName(DB),
|
|
storedBBoxSize(DB,SimpleTerm,Size), !. % already known
|
|
|
|
% --- bboxSizeQueryJoin(+Term,+Rel1,+Rel2,+TermTypeTree,-Size)
|
|
bboxSizeQueryJoin(Term,Rel1,Rel2,[_,_,T],Size) :-
|
|
dm(selectivity,['\nbboxSizeQueryJoin(',Term,', ',Rel1,', ',Rel2,', [_,_,',
|
|
T,'], ',Size,') called!\n']),
|
|
( isKind(T,spatial2d) ; memberchk(T,[rect,rect3,rect4,rect8,
|
|
mpoint,upoint,ipoint,
|
|
instant,periods,
|
|
movingregion,intimeregion,uregion]) ),
|
|
simple(Term, [(1,Rel1),(2,Rel2)], SimpleTerm),
|
|
Rel1 = rel(DCrelName1, _),
|
|
Rel2 = rel(DCrelName2, _),
|
|
transformPred(Term, txx1, 1, Term2),
|
|
newVariable(NewAttr),
|
|
secOptConstant(sampleTimeout, Timeout),
|
|
( optimizerOption(dynamicSample)
|
|
-> ( dynamicPossiblyRenameJ(Rel1, Rel1Query),
|
|
dynamicPossiblyRenameJ(Rel2, Rel2Query),
|
|
( optimizerOption(subqueries)
|
|
-> % Old method uses faster loopjoin:
|
|
SizeQueryT = avg(timeout(projectextend(
|
|
loopjoin(Rel1Query, fun([param(txx1, tuple)], Rel2Query)),
|
|
[],
|
|
[field(attr(NewAttr,0,l),size(bbox(Term2)))]),Timeout),NewAttr)
|
|
; % New version uses slower symmproduct to enable a balanced stream
|
|
% consumption within the timeout
|
|
SizeQueryT = avg(timeout(projectextend(
|
|
symmproduct(Rel1Query, Rel2Query),
|
|
[],
|
|
[field(attr(NewAttr,0,l),size(bbox(Term)))]),
|
|
value_expr(real,Timeout)), attrname(attr(NewAttr,0,l)))
|
|
)
|
|
)
|
|
; ( ensureSampleSexists(DCrelName1),
|
|
ensureSampleJexists(DCrelName2),
|
|
sampleS(Rel1, Rel1S),
|
|
sampleJ(Rel2, Rel2S),
|
|
possiblyRename(Rel1S, Rel1Query),
|
|
possiblyRename(Rel2S, Rel2Query),
|
|
secOptConstant(sampleJoinMaxCard, JoinSize),
|
|
( optimizerOption(subqueries)
|
|
-> % Old method uses faster loopjoin:
|
|
SizeQueryT = avg(timeout(projectextend(
|
|
loopjoin(head(Rel1Query, JoinSize),
|
|
fun([param(txx1, tuple)], head(Rel2Query,JoinSize))),
|
|
[],
|
|
[field(attr(NewAttr,0,l),size(bbox(Term2)))]),
|
|
value_expr(real,Timeout)), attrname(attr(NewAttr,0,l)))
|
|
; % New version uses slower symmproduct to enable a balanced stream
|
|
% consumption within the timeout
|
|
SizeQueryT = avg(timeout(projectextend(
|
|
symmproduct(head(Rel1Query,JoinSize),head(Rel2Query,JoinSize)),
|
|
[],
|
|
[field(attr(NewAttr,0,l),size(bbox(Term)))]),
|
|
value_expr(real,Timeout)), attrname(attr(NewAttr,0,l)))
|
|
)
|
|
)
|
|
),
|
|
plan_to_atom(SizeQueryT,SizeQueryA),
|
|
my_concat_atom(['query ',SizeQueryA],'',SizeQuery),
|
|
dm(selectivity,['\nThe Avg-Size Query is: ', SizeQuery, '\n']),
|
|
!, % no backtracking before this!
|
|
secondo(SizeQuery,[real,Size]),
|
|
dm(selectivity,['\nThe Avg-Size is: ', Size, '\n']),
|
|
databaseName(DB),
|
|
assert(storedBBoxSize(DB,SimpleTerm,Size)), !. % store it
|
|
|
|
bboxSizeQueryJoin(Term,Rel1,Rel2,[_,_,T],none) :- % no bbox available
|
|
dm(selectivity,['bboxSizeQueryJoin/5: Term \'',Term,'\' for relations ',Rel1,
|
|
' and ',Rel2,' has Type ',T,', but no bbox!\n\n']),!.
|
|
|
|
/*
|
|
Now, we are prepared to formulate the actual predicates committing the
|
|
selectivity queries:
|
|
|
|
*/
|
|
|
|
/*
|
|
1.3.1 Spatial Selection Predicate with Bounding-Box-Checking
|
|
|
|
*/
|
|
|
|
% spatial selection predicate with bbox-checking
|
|
selectivityQuerySelection(Pred, Rel, QueryTime, BBoxResCard,
|
|
FilterResCard, InputCard) :-
|
|
Pred =.. [OP, Arg1, Arg2],
|
|
( optimizerOption(determinePredSig)
|
|
-> ( getTypeTree(Pred,[(1,Rel)],[OP,ArgsTrees,bool]),
|
|
extractSignature(ArgsTrees,ArgsTypeList),
|
|
isBBoxOperator(OP,ArgsTypeList,Dim),
|
|
getBBoxIntersectionTerm(Arg1,Arg2,Dim,BBoxPred),
|
|
ArgsTrees = [Arg1Tree,Arg2Tree],
|
|
bboxSizeQuerySel(Arg1,Rel,Arg1Tree,_),
|
|
bboxSizeQuerySel(Arg2,Rel,Arg2Tree,_)
|
|
)
|
|
; ( isBBoxPredicate(OP),
|
|
getBBoxIntersectionTerm(Arg1,Arg2,std,BBoxPred)
|
|
)
|
|
),
|
|
( optimizerOption(dynamicSample)
|
|
-> dynamicPossiblyRenameS(Rel, RelQuery)
|
|
; ( Rel = rel(DCrelName, _),
|
|
ensureSampleSexists(DCrelName),
|
|
sampleS(Rel, RelS),
|
|
possiblyRename(RelS, RelQuery)
|
|
)
|
|
),
|
|
dm(selectivity,['\n==== spatial unary predicate with bbox-checking: '
|
|
,Pred,' ====\n']),
|
|
secOptConstant(sampleTimeout, Timeout),
|
|
secOptConstant(selTestSize, SelTestSize),
|
|
Query =
|
|
count(timeout(filter(counter(filter(counter(head(RelQuery, SelTestSize),1),
|
|
BBoxPred),2), Pred),value_expr(real,Timeout))),
|
|
transformQuery(Rel, Pred, Query, Query2),
|
|
plan_to_atom(Query2, QueryAtom1),
|
|
atom_concat('query ', QueryAtom1, QueryAtom),
|
|
dm(selectivity,['\nSelectivity query : ', QueryAtom, '\n']),
|
|
getTime(
|
|
( secondo(QueryAtom, ResultList)
|
|
-> (true)
|
|
; ( term_to_atom(Pred, PredA),
|
|
my_concat_atom(['Selectivity query failed: Please check ',
|
|
'whether predicate \'', PredA, '\' is a boolean ',
|
|
'function! Possibly a database object is missing.'
|
|
],'',ErrorMsg),
|
|
write_list(['\nERROR:\t',ErrorMsg,' ']), nl,
|
|
throw(error_SQL(statistics_selectivityQuerySelection(Pred, Rel,
|
|
QueryTime, BBoxResCard, FilterResCard, InputCard)
|
|
::selectivityQueryFailed::ErrorMsg)),
|
|
fail
|
|
)
|
|
)
|
|
,QueryTime
|
|
),
|
|
clearSelectivityQuery(Rel, Pred),
|
|
( ResultList = [int, FilterResCard]
|
|
-> true
|
|
; ( write_list(['\nERROR:\tUnexpected result list format during ',
|
|
'selectivity query:\n',
|
|
'Expected \'[int, <intvalue>]\' but got \'',
|
|
ResultList, '\'.']), nl,
|
|
throw(error_Internal(statistics_selectivityQuerySelection(
|
|
Pred, Rel, QueryTime, BBoxResCard,FilterResCard,InputCard)
|
|
::unexpectedListType)),
|
|
fail
|
|
)
|
|
),
|
|
dm(selectivity,['Elapsed Time: ', QueryTime, ' ms\n']),
|
|
secondo('list counters', ResultList2),
|
|
( ResultList2 = [[1, InputCard],[2, BBoxResCard]|_]
|
|
-> true
|
|
; ( write_list(['\nERROR:\tUnexpected result list format during ',
|
|
'list counters query:\n',
|
|
'Expected \'[[1, InputCard],[2, BBoxResCard]|_]\' but got \'',
|
|
ResultList2, '\'.']), nl,
|
|
throw(error_Internal(statistics_selectivityQuerySelection(
|
|
Pred, Rel, QueryTime, BBoxResCard,FilterResCard,InputCard)
|
|
::unexpectedListType)),
|
|
fail
|
|
)
|
|
),
|
|
!.
|
|
|
|
/*
|
|
1.3.1 Selection Predicate with Index Support (=, starts)
|
|
|
|
For simple predicates of the form 'attrname = value' on strings or integers, or of the form 'attrname starts value' on strings, there is a special support as follows. From the Rel\_sample\_s, an index is built as an ordered relation with the name Rel\_AttrName\_Cnt. For each attribute value it has the number of tuples in the sample with this value. The index is built automatically on the first selectivity query with a predicate of the above form.
|
|
|
|
The selectivity query is then evaluated by a query on the index.
|
|
|
|
For relations up to several million tuples, the index on the sample is built in less than a second. Furtheron, selectivity queries of these forms require only about 30 ms for evaluation. In contrast, on larger samples they might require a few hundred milliseconds if evaluated in the standard way, i.e., checking all tuples of the sample.
|
|
|
|
*/
|
|
|
|
selectivityQuerySelection(Pred, Rel, QueryTime, noBBox, ResCard, InputCard) :-
|
|
not(optimizerOption(dynamicSample)),
|
|
write('Pred = '), write(Pred), nl,
|
|
write('Rel = '), write(Rel), nl,
|
|
( ( Pred = (attr(AttrName, _, _) = value_expr(Type, List)),
|
|
member(Type, [string, int]) );
|
|
( Pred = (attr(AttrName, _, _) starts value_expr(Type, List)),
|
|
member(Type, [string]))
|
|
),
|
|
plan_to_atom(value_expr(Type, List), Val),
|
|
Rel = rel(DCRel, _),
|
|
dcName2externalName(DCRel, ExtRel),
|
|
( AttrName = _:Suffix -> Name = Suffix; Name = AttrName ),
|
|
internalName2externalName(Name, ExtAttrName),
|
|
ensureSampleSexists(DCRel),
|
|
my_concat_atom([ExtRel, '_', ExtAttrName, '_Cnt'],'', CntIndex),
|
|
my_concat_atom(['query isDBObject("', CntIndex, '")'], '', Query1),
|
|
write('Query1 = '), write(Query1), nl,
|
|
secondo(Query1, Result1),
|
|
write('Result = '), write(Result1), nl,
|
|
( Result1 = [bool, false] ->
|
|
( my_concat_atom(['let ', CntIndex, ' = ',
|
|
ExtRel, '_sample_s feed project[', ExtAttrName,
|
|
'] sort groupby[', ExtAttrName, '; Cnt: group count] oconsume[',
|
|
ExtAttrName, ']' ], '', Query3) ,
|
|
write('Query3 = '), write(Query3), nl,
|
|
secondo(Query3) )
|
|
; true
|
|
),
|
|
( Pred =.. [=, _, _] ->
|
|
my_concat_atom(['query ', CntIndex, ' orange[', Val, '; ', Val,
|
|
'] extract[Cnt]'], '', Query2);
|
|
Pred =.. [starts, _, _] ->
|
|
my_concat_atom(['query ', CntIndex, ' orange[', Val, '; ', Val,
|
|
'++] sum[Cnt]'], '', Query2)
|
|
),
|
|
write('Query2 = '), write(Query2), nl, nl,
|
|
secondo(Query2, ResultList),
|
|
write('ResultList = '), write(ResultList), nl, nl,
|
|
ResultList = [int, Res],
|
|
( Res = undefined -> ResCard is 1 ; ResCard = Res ),
|
|
getSampleSname(DCRel, Sample),
|
|
card(Sample, InputCard),
|
|
QueryTime is 1.0e-6,
|
|
!.
|
|
|
|
/*
|
|
1.3.1 Other Selection Predicate
|
|
|
|
*/
|
|
|
|
% normal selection predicate
|
|
selectivityQuerySelection(Pred, Rel, QueryTime, noBBox, ResCard, InputCard) :-
|
|
Pred =.. [OP|_],
|
|
( optimizerOption(determinePredSig)
|
|
-> ( getTypeTree(Pred,[(1,Rel)],[OP,ArgsTrees,bool]),
|
|
extractSignature(ArgsTrees,ArgsTypeList),
|
|
not(isBBoxOperator(OP,ArgsTypeList,_))
|
|
)
|
|
; not(isBBoxPredicate(OP))
|
|
),
|
|
( optimizerOption(dynamicSample)
|
|
-> dynamicPossiblyRenameS(Rel, RelQuery)
|
|
; ( Rel = rel(DCrelName, _),
|
|
ensureSampleSexists(DCrelName),
|
|
sampleS(Rel, RelS),
|
|
possiblyRename(RelS, RelQuery)
|
|
)
|
|
),
|
|
dm(selectivity,['\n------------- unary standard predicate: ',
|
|
Pred,' -------------\n']),
|
|
secOptConstant(sampleTimeout, Timeout),
|
|
secOptConstant(selTestSize, SelTestSize),
|
|
Query = count(timeout(filter(counter(head(RelQuery, SelTestSize), 1), Pred),
|
|
value_expr(real,Timeout))),
|
|
transformQuery(Rel, Pred, Query, Query2),
|
|
plan_to_atom(Query2, QueryAtom1),
|
|
atom_concat('query ', QueryAtom1, QueryAtom),
|
|
dm(selectivity,['\nSelectivity query : ', QueryAtom, '\n']),
|
|
getTime(
|
|
( secondo(QueryAtom, ResultList)
|
|
-> (true)
|
|
; ( term_to_atom(Pred,PredA),
|
|
my_concat_atom(['Selectivity query failed. Please check ',
|
|
'whether predicate \'', PredA, '\' is a boolean ',
|
|
'function! '],'',ErrMsg),
|
|
write_list(['\nERROR:\t',ErrMsg]), nl,
|
|
throw(error_SQL(statistics_selectivityQuerySelection(Pred, Rel,
|
|
QueryTime, noBBox, ResCard, InputCard)
|
|
::selectivityQueryFailed::ErrMsg)),
|
|
fail
|
|
)
|
|
)
|
|
,QueryTime
|
|
),
|
|
clearSelectivityQuery(Rel, Pred),
|
|
( ResultList = [int, ResCard]
|
|
-> true
|
|
; ( write_list(['\nERROR:\tUnexpected result list format during ',
|
|
'selectivity query:\n',
|
|
'Expected \'[int, <intvalue>]\' but got \'',
|
|
ResultList, '\'.']), nl,
|
|
throw(error_Internal(statistics_selectivityQuerySelection(
|
|
Pred, Rel, QueryTime, noBBox, ResCard, InputCard)
|
|
::unexpectedListType)),
|
|
fail
|
|
)
|
|
),
|
|
dm(selectivity,['Elapsed Time: ', QueryTime, ' ms\n']),
|
|
secondo('list counters', ResultList2),
|
|
( ResultList2 = [[1, InputCard]|_]
|
|
-> true
|
|
; ( write_list(['\nERROR:\tUnexpected result list format during ',
|
|
'list counters query:\n',
|
|
'Expected \'[[1, InputCard]|_]\' but got \'',
|
|
ResultList2, '\'.']), nl,
|
|
throw(error_Internal(statistics_selectivityQuerySelection(
|
|
Pred, Rel, QueryTime, noBBox, ResCard, InputCard)
|
|
::unexpectedListType)),
|
|
fail
|
|
)
|
|
),
|
|
!.
|
|
|
|
selectivityQuerySelection(Pred, Rel, QueryTime, BBox, ResCard, InputCard) :-
|
|
write_list(['\nERROR:\tSelectivity query failed for unknown reason.']), nl,
|
|
throw(error_Internal(statistics_selectivityQuerySelection(Pred, Rel,QueryTime,
|
|
BBox, ResCard, InputCard)::selectivityQueryFailed)), fail.
|
|
|
|
/*
|
|
1.3.1 Spatial Join Predicate with Bounding-Box-Checking
|
|
|
|
*/
|
|
|
|
% spatial join predicate with bbox-checking
|
|
selectivityQueryJoin(Pred, Rel1, Rel2, QueryTime, BBoxResCard, FilterInputCard,
|
|
TotalResCard, InputCard) :-
|
|
Pred =.. [OP, Arg1, Arg2],
|
|
( optimizerOption(determinePredSig)
|
|
-> ( getTypeTree(Pred,[(1,Rel1),(2,Rel2)],[OP,ArgsTrees,bool]),
|
|
extractSignature(ArgsTrees,ArgsTypeList),
|
|
isBBoxOperator(OP,ArgsTypeList,_Dim),
|
|
ArgsTrees = [Arg1Tree,Arg2Tree],
|
|
bboxSizeQueryJoin(Arg1,Rel1,Rel2,Arg1Tree,_),
|
|
bboxSizeQueryJoin(Arg2,Rel1,Rel2,Arg2Tree,_)
|
|
)
|
|
; ( isBBoxPredicate(OP)
|
|
% Dim = std
|
|
)
|
|
),
|
|
|
|
dm(selectivity,['\n==== spatial binary predicate with bbox-checking: ',
|
|
Pred,' ====\n']),
|
|
|
|
% secOptConstant(sampleTimeout, Timeout),
|
|
( optimizerOption(dynamicSample)
|
|
-> ( dynamicPossiblyRenameJ(Rel1, Rel1Query),
|
|
dynamicPossiblyRenameJ(Rel2, Rel2Query)
|
|
)
|
|
; ( Rel1 = rel(DCrelName1, _),
|
|
Rel2 = rel(DCrelName2, _),
|
|
ensureSampleSexists(DCrelName1),
|
|
ensureSampleJexists(DCrelName2),
|
|
sampleS(Rel1, Rel1S),
|
|
sampleJ(Rel2, Rel2S),
|
|
possiblyRename(Rel1S, Rel1Query),
|
|
possiblyRename(Rel2S, Rel2Query)
|
|
)
|
|
),
|
|
|
|
/*
|
|
The problem is here to determine (i) the bounding box selectivity within the filter step, and (ii) the refinement selectivity and the predicate cost of the refinement step.
|
|
|
|
We use the following method:
|
|
|
|
1 A spatial join is performed on the two samples. We collect up to one hundred result pairs and store them in a relation xxxTemp.
|
|
|
|
2 Let ~n~ be the number of results stored in x
|
|
xxTemp. If ~n~ is 0, we set the bbox-selectivity to 1/(cardinality of the input). Further we set the refinement selectivity to 1 and the predicate cost to 1.0 ms (as we really don't know).
|
|
|
|
3 We run the query 'xxxTemp feed filter[Pred] count' to determine the refinement selectivity. As usual, if the result is 0, we set it to 1, hence then the refinement selectivity is 1/n.
|
|
|
|
4 If ~n~ is greater 0, we set the bbox-selectivity to n/(cardinality of the input). Further we determine an integer factor ~f~ to enlarge the result size to about 100. That is, f = 100 div n. This means that n * f is close to 100 and at least 51.
|
|
|
|
5 We run the query 'intstream(1, f) transformstream extend[X: XxxTemp feed count] count' three times and determine the average running time ~Tbase~.
|
|
|
|
6 We run the query 'intstream(1, f) transformstream extend[X: XxxTemp feed {1} filter[Pred] count] count' three times and determine the average running time ~Tbrutto~. Let Tpred = Tbrutto - Tbase. We then set the predicate cost to Tpred / (n * f).
|
|
|
|
*/
|
|
|
|
% step 1
|
|
Arg1 = attr(_, _, _),
|
|
Arg2 = attr(_, _, _),
|
|
Query1 = consume(
|
|
head(
|
|
itSpatialJoin(counter(Rel1Query, 1), counter(Rel2Query, 2),
|
|
attrname(Arg1), attrname(Arg2)),
|
|
100)),
|
|
|
|
( secondo('query isDBObject("xxxTemp")', [bool, true]) -> delete 'xxxTemp'
|
|
; true ),
|
|
|
|
plan_to_atom(Query1, QueryAtom1a),
|
|
atom_concat('let xxxTemp = ', QueryAtom1a, QueryAtom1),
|
|
dm(selectivity,['\nSelectivity query 1: ', QueryAtom1, '\n']),
|
|
secondo(QueryAtom1, _),
|
|
|
|
secondo('list counters', ResultList1),
|
|
ResultList1 = [[1, InputCardRel1], [2, InputCardRel2] |_],
|
|
|
|
InputCard is InputCardRel1 * InputCardRel2,
|
|
write_list(['InputCard = ', InputCard]), nl,
|
|
write_list(['InputCard1 = ', InputCardRel1]), nl,
|
|
write_list(['InputCard2 = ', InputCardRel2]), nl,
|
|
|
|
|
|
|
|
% step 2 check whether resultsize is 0.
|
|
secondo('query xxxTemp count', [int, Card]),
|
|
( Card = 0 ->
|
|
( BBoxResCard = 0, FilterInputCard = 0, TotalResCard = 0,
|
|
QueryTime = 1.0 )
|
|
;
|
|
|
|
( BBoxResCard = Card,
|
|
|
|
% all the remainder of this predicate is the else-branch with Card > 0.
|
|
|
|
% step 3 determine selectivity of refinement step.
|
|
secOptConstant(sampleTimeout, TimeOut),
|
|
Query2 =
|
|
count(
|
|
timeout(
|
|
filter(counter(feed(xxxTemp), 1), Pred),
|
|
value_expr(real, TimeOut))),
|
|
|
|
% Pred for example: attr(r:geoData,1,u)intersects attr(n:geoData,2,u)
|
|
|
|
plan_to_atom(Query2, QueryAtom2a),
|
|
atom_concat('query ', QueryAtom2a, QueryAtom2),
|
|
dm(selectivity,['\nSelectivity query 2: ', QueryAtom2, '\n']),
|
|
|
|
( secondo(QueryAtom2, ResultList3)
|
|
-> (true)
|
|
; ( write_list(['\nERROR:\tSelectivity query failed. Please check ',
|
|
'whether predicate \'', Pred, '\' is a boolean ',
|
|
'function! ']), nl,
|
|
throw(error_Internal(statistics_selectivityQueryJoin(
|
|
Pred, Rel1, Rel2, QueryTime, BBoxResCard, FilterInputCard,
|
|
TotalResCard, InputCard)::selectivityQueryFailed)),
|
|
fail
|
|
)
|
|
),
|
|
|
|
ResultList3 = [int, FilterResCard],
|
|
secondo('list counters', ResultList4),
|
|
ResultList4 = [[1, FilterInputCardA] |_],
|
|
write_list(['FilterInputCard = ', FilterInputCardA]), nl,
|
|
write_list(['FilterResultCard = ', FilterResCard]), nl,
|
|
FilterSel is (FilterResCard / FilterInputCardA),
|
|
TotalResCard is BBoxResCard * FilterSel,
|
|
write_list(['TotalResultCard = ', TotalResCard]), nl,
|
|
|
|
|
|
% step 4 determine factor
|
|
Factor is 100 // BBoxResCard,
|
|
|
|
% step 5 + 6 determine PET
|
|
% step 5 run base query
|
|
Query3 =
|
|
count(
|
|
extend(
|
|
transformstream(intstream(1, Factor)),
|
|
[field( attr(x, 0, u), count(feed(xxxTemp)) )])),
|
|
|
|
plan_to_atom(Query3, QueryAtom3a),
|
|
atom_concat('query ', QueryAtom3a, QueryAtom3),
|
|
dm(selectivity,['\nSelectivity query 3: ', QueryAtom3, '\n']),
|
|
|
|
getTime(
|
|
( secondo(QueryAtom3, _),
|
|
secondo(QueryAtom3, _),
|
|
secondo(QueryAtom3, _)
|
|
),
|
|
Tbase
|
|
),
|
|
|
|
|
|
% step 6 run refinement query
|
|
% intstream(1, Factor) transformstream extend[X: xxxTemp feed {1}
|
|
% filter[Pred] timeout[3.5] count
|
|
Query4 =
|
|
count(
|
|
timeout(
|
|
extend(
|
|
transformstream(intstream(1, Factor)),
|
|
[field( attr(x, 0, u),
|
|
count(filter(counter(feed(xxxTemp), 1), Pred)) )]),
|
|
value_expr(real, 3.5))),
|
|
|
|
plan_to_atom(Query4, QueryAtom4a),
|
|
atom_concat('query ', QueryAtom4a, QueryAtom4),
|
|
dm(selectivity,['\nSelectivity query 4: ', QueryAtom3, '\n']),
|
|
|
|
getTime(
|
|
( secondo(QueryAtom4, _),
|
|
secondo('list counters', [[1, FilterInputCard1] |_]),
|
|
secondo(QueryAtom4, _),
|
|
secondo('list counters', [[1, FilterInputCard2] |_]),
|
|
secondo(QueryAtom4, _),
|
|
secondo('list counters', [[1, FilterInputCard3] |_])
|
|
),
|
|
Tbrutto
|
|
),
|
|
write_list(['BBoxResCard = ', BBoxResCard]), nl,
|
|
write_list(['Tbase = ', Tbase]), nl,
|
|
write_list(['Tbrutto = ', Tbrutto]), nl,
|
|
|
|
QueryTime is (Tbrutto - Tbase),
|
|
FilterInputCard is
|
|
FilterInputCard1 + FilterInputCard2 + FilterInputCard3,
|
|
|
|
write_list(['FilterInputCard = ', FilterInputCard]), nl,
|
|
write_list(['QueryTime = ', QueryTime]), nl
|
|
|
|
)
|
|
),
|
|
!.
|
|
|
|
|
|
/*
|
|
1.3.1 Normal Join Predicate
|
|
|
|
*/
|
|
|
|
% normal join predicate
|
|
selectivityQueryJoin(Pred, Rel1, Rel2, QueryTime1, noBBox, _,
|
|
ResCard1, InputCard1) :-
|
|
Pred =.. [OP|_],
|
|
( optimizerOption(determinePredSig)
|
|
-> ( getTypeTree(Pred,[(1,Rel1),(2,Rel2)],[OP,ArgsTrees,bool]),
|
|
extractSignature(ArgsTrees,ArgsTypeList),
|
|
not(isBBoxOperator(OP,ArgsTypeList,_))
|
|
)
|
|
; true % not(isBBoxPredicate(OP))
|
|
),
|
|
( optimizerOption(subqueries)
|
|
-> ( streamName(txx1),
|
|
assert(selectivityQuery(Pred)),
|
|
transformPred(Pred, txx1, 1, Pred2)
|
|
)
|
|
; Pred2 = Pred
|
|
),
|
|
dm(selectivity,['\n------------- binary standard predicate: ',
|
|
Pred2,' -------------\n']),
|
|
|
|
|
|
|
|
( optimizerOption(dynamicSample)
|
|
-> ( dynamicPossiblyRenameJ(Rel1, Rel1Query),
|
|
dynamicPossiblyRenameJ(Rel2, Rel2Query)
|
|
)
|
|
; ( Rel1 = rel(DCrelName1, _),
|
|
Rel2 = rel(DCrelName2, _),
|
|
ensureSampleSexists(DCrelName1),
|
|
ensureSampleJexists(DCrelName1),
|
|
ensureSampleJexists(DCrelName2),
|
|
sampleS(Rel1, Rel1S),
|
|
sampleJ(Rel2, Rel2S),
|
|
possiblyRename(Rel1S, Rel1Query),
|
|
possiblyRename(Rel2S, Rel2Query)
|
|
)
|
|
),
|
|
write('Join predicate Pred2 is: '), write(Pred2), nl,
|
|
write('Rel1Query is: '), write(Rel1Query), nl,
|
|
write('Rel2Query is: '), write(Rel2Query), nl,
|
|
write('Join predicate Pred is: '), write(Pred), nl,
|
|
write('Rel2 is: '), write(Rel2), nl,
|
|
|
|
standardJoinQuery(Rel1Query, Rel2Query, Pred2, Rel1, Rel2, Pred,
|
|
JoinSize, Query),
|
|
|
|
plan_to_atom(Query, QueryAtom1),
|
|
atom_concat('query ', QueryAtom1, QueryAtom),
|
|
dm(selectivity,['\nSelectivity query : ', QueryAtom, '\n']),
|
|
getTime(
|
|
( secondo(QueryAtom, ResultList)
|
|
-> (true)
|
|
; ( write_list(['\nERROR:\tSelectivity query failed. Please check ',
|
|
'whether predicate \'', Pred, '\' is a boolean ',
|
|
'function! ']), nl,
|
|
throw(error_Internal(statistics_selectivityQueryJoin(Pred, Rel1,Rel2,
|
|
QueryTime1, noBBox, _, ResCard1, InputCard1)
|
|
::selectivityQueryFailed)),
|
|
fail
|
|
)
|
|
)
|
|
,QueryTime
|
|
),
|
|
( optimizerOption(subqueries)
|
|
-> ( clearSelectivityQuery(Rel1, Rel2, Pred),
|
|
clearStreamName
|
|
)
|
|
; true
|
|
),
|
|
( ResultList = [int, ResCard]
|
|
-> true
|
|
; ( write_list(['\nERROR:\tUnexpected result list format during ',
|
|
'selectivity query:\n',
|
|
'Expected \'[int, <intvalue>]\' but got \'',
|
|
ResultList, '\'.']), nl,
|
|
throw(error_Internal(statistics_selectivityQueryJoin(
|
|
Pred, Rel1, Rel2, QueryTime1, noBBox, _, ResCard1,
|
|
InputCard1)::unexpectedListType)),
|
|
fail
|
|
)
|
|
),
|
|
secondo('list counters', ResultList2),
|
|
( ResultList2 = [[1, InputCardRel1],[2, InputCardRel2] | _ ]
|
|
-> true
|
|
; ( write_list(['\nERROR:\tUnexpected result list format during ',
|
|
'list counters query:\n',
|
|
'Expected \'[[1, InputCardRel1],[2, InputCardRel2]|_]\' ',
|
|
'but got \'', ResultList2, '\'.']), nl,
|
|
throw(error_Internal(statistics_selectivityQuerySelection(
|
|
Pred, Rel1, Rel2, QueryTime1, noBBox, ResCard1, InputCard1)
|
|
::unexpectedListType)),
|
|
fail
|
|
)
|
|
),
|
|
( ( optimizerOption(subqueries),
|
|
not(Pred =.. [=, attr(_, _, _), attr(_, _, _)]) )
|
|
-> InputCard = InputCardRel2
|
|
; InputCard is InputCardRel1 * InputCardRel2
|
|
),
|
|
% InputCard is InputCardRel1 * InputCardRel2,
|
|
write_list(['InputCard = ', InputCard]), nl,
|
|
write_list(['InputCard1 = ', InputCardRel1]), nl,
|
|
write_list(['InputCard2 = ', InputCardRel2]), nl,
|
|
( realJoinSize(Pred, S)
|
|
-> ( ResCard1 is ResCard * JoinSize / S,
|
|
QueryTime1 is QueryTime * JoinSize / S,
|
|
InputCard1 is InputCard * JoinSize / S,
|
|
retractall(realJoinSize(Pred, _)) )
|
|
; ( ResCard1 = ResCard, QueryTime1 = QueryTime, InputCard1 = InputCard )
|
|
),
|
|
write_list(['ResultCard = ', ResCard1]), nl,
|
|
( not(ResCard1 = 100000)
|
|
; ( sampleJ(Rel2, rel(Rel2Sample, _)),
|
|
card(Rel2Sample, C2),
|
|
InputCardRel2 < C2 )
|
|
), % for itHashjoin: either the output cardinality was not limited
|
|
% or the second input stream was not consumed completely
|
|
|
|
dm(selectivity,['Elapsed Time: ', QueryTime, ' ms\n']), !.
|
|
|
|
selectivityQueryJoin(Pred, Rel1, Rel2, QueryTime, BBox,
|
|
FilterInputCard, ResCard, InputCard) :-
|
|
term_to_atom(Pred,PredT),
|
|
my_concat_atom(['Selectivity query failed for: \'',PredT,
|
|
'\'. Unknown reason.'],'',ErrMsg),
|
|
write_list(['\nERROR:\t',ErrMsg]), nl,
|
|
throw(error_Internal(statistics_selectivityQueryJoin(Pred, Rel1, Rel2,
|
|
QueryTime, BBox, FilterInputCard,
|
|
ResCard, InputCard)::selectivityQueryFailed)), fail.
|
|
|
|
|
|
standardJoinQuery(Rel1Query, Rel2Query, _, _, _, Pred,
|
|
_, Query) :-
|
|
Pred =.. [=, Arg1, Arg2],
|
|
Arg1 = attr(_, _, _),
|
|
Arg2 = attr(_, _, _),
|
|
Query = count(head(itHashJoin(
|
|
counter(Rel1Query, 1),
|
|
counter(Rel2Query, 2), attrname(Arg1), attrname(Arg2)), 100000)).
|
|
|
|
|
|
standardJoinQuery(Rel1Query, Rel2Query, Pred2, Rel1, Rel2, Pred,
|
|
JoinSize, Query2) :-
|
|
secOptConstant(sampleTimeout, Timeout),
|
|
secOptConstant(sampleJoinMaxCard, JoinSize),
|
|
( optimizerOption(subqueries)
|
|
-> ( Query = count(timeout(loopsel(counter(Rel1Query,1),
|
|
fun([param(txx1, tuple)],
|
|
filter(counter(Rel2Query,2), Pred2))), Timeout)),
|
|
transformQuery(Rel1, Rel2, Pred, Query, JoinSize, Query2)
|
|
)
|
|
; (
|
|
Query2 = count(timeout(symmjoin(
|
|
counter(head(Rel1Query, JoinSize), 1),
|
|
counter(head(Rel2Query, JoinSize), 2),
|
|
Pred), value_expr(real, Timeout)))
|
|
)
|
|
).
|
|
|
|
|
|
/*
|
|
|
|
---- transformPred(+Pred, +Param, +Arg, -Pred2)
|
|
----
|
|
|
|
~Pred2~ is ~Pred~ transformed such that the attribute X of relation ~ArgNo~ is
|
|
written as ``attribute(Param, attrname(X))''
|
|
|
|
*/
|
|
|
|
% handle subqueries
|
|
transformPred(Pred, Param, Arg, Pred2) :-
|
|
optimizerOption(subqueries),
|
|
subqueryTransformPred(Pred, Param, Arg, Pred2).
|
|
|
|
transformPred(attr(Attr, Arg, Case), Param, Arg,
|
|
attribute(Param, attrname(attr(Attr, Arg, Case)))) :- !.
|
|
|
|
transformPred(attr(Attr, Arg, Case), _, _, attr(Attr, Arg, Case)) :- !.
|
|
|
|
transformPred([], _, _, []).
|
|
transformPred([Arg1|Args1], Param, Arg, [Arg1T|Args1T]) :-
|
|
transformPred(Arg1, Param, Arg, Arg1T),
|
|
transformPred(Args1, Param, Arg, Args1T).
|
|
|
|
transformPred(Pred, Param, Arg, Pred2) :-
|
|
compound(Pred),
|
|
Pred =.. [T|Args],
|
|
transformPred(Args, Param, Arg, Args2),
|
|
Pred2 =.. [T|Args2].
|
|
|
|
transformPred(Pred, _, _, Pred).
|
|
|
|
|
|
% Selectivities must not be 0
|
|
|
|
nonzero(0, 1) :- !.
|
|
|
|
nonzero(N, N).
|
|
|
|
/*
|
|
---- getTime(:Goal, -Time)
|
|
----
|
|
|
|
Measures the time used to execute ~Goal~ in milliseconds (ms).
|
|
|
|
*/
|
|
|
|
getTime(Goal, TimeMS) :-
|
|
get_time(Time1),
|
|
call(Goal),
|
|
get_time(Time2),
|
|
Time3 is Time2 - Time1,
|
|
my_convert_time(Time3, _, _, _, _, Minute, Sec, MilliSec),
|
|
TimeMS is Minute *60000 + Sec*1000 + MilliSec, !.
|
|
|
|
/*
|
|
|
|
----
|
|
selectivity(+P, -Sel)
|
|
selectivity(+P, -Sel, -CalcPET, -ExpPET)
|
|
getPET(+P, -CalcPET, -ExpPET)
|
|
getBBoxSel(+P, -BBoxSel)
|
|
----
|
|
|
|
The selectivity of predicate ~P~ is ~Sel~. The analytic predicate cost function
|
|
reports the evaluation of the predicate to take ~CalcPET~ milliseconds of time.
|
|
During the actual query, the evaluation took ~ExpPET~ milliseconds of time for
|
|
a single evaluation.
|
|
|
|
If ~selectivity~ is called, it first tries to look up
|
|
the selectivity via the predicate ~sels~. If no selectivity
|
|
is found, a Secondo query is issued, which determines the
|
|
selectivity. The retrieved selectitivity is then stored in
|
|
predicate ~storedSel~. This ensures that a selectivity has to
|
|
be retrieved only once.
|
|
|
|
Additionally, the time to evaluate a predicate is estimated by
|
|
dividing the query time by the number of predicate evaluations.
|
|
The result is stored in a table ~storedPET(DB, Pred, CalcPET, ExpPET)~, where
|
|
~PET~ means ~Predicate Evaluation Time~.
|
|
|
|
Bounding Box selectivity and Predicate Evaluation Times are available using
|
|
predicates ~getPET/3~ ans ~getBBoxSel/2~.
|
|
|
|
It is possible to fake a predicate. In this case, you can explicitely state a
|
|
given selectivity, bbox-selectivity, calculated and experimental PET. This is
|
|
done using the ``predicate'' (May be useful for testing cost functions.):
|
|
|
|
---- fakePred(+Sel,+BboxSel,+CalcPET,+ExpPET)
|
|
----
|
|
|
|
*/
|
|
|
|
% faked predicate:
|
|
sels(pr(fakePred(Sel,BboxSel,CalcPET,ExpPET), Sel, ClacPET, ExpPET)) :-
|
|
( (ground(Sel), ground(BboxSel), ground(CalcPET), ground(ExpPET))
|
|
-> true
|
|
; throw(error_Internal(statistics_sels(pr(fakePred(Sel,BboxSel,CalcPET,
|
|
ExpPET)),Sel,ClacPET,ExpPET)::fakePred_requires_ground_arguments))
|
|
),
|
|
!.
|
|
|
|
sels(Pred, Sel, CalcPET, ExpPET) :-
|
|
databaseName(DB),
|
|
storedSel(DB, Pred, Sel),
|
|
storedPET(DB, Pred, CalcPET, ExpPET), !.
|
|
|
|
sels(Pred, Sel, CalcPET, ExpPET) :-
|
|
commute(Pred, Pred2),
|
|
databaseName(DB),
|
|
storedSel(DB, Pred2, Sel),
|
|
storedPET(DB, Pred2, CalcPET, ExpPET), !.
|
|
|
|
% Wrapper selectivity/2 for standard optimizer
|
|
selectivity(Pred, Sel) :-
|
|
selectivity(Pred, Sel, _, _).
|
|
|
|
selectivity(P, X) :-
|
|
write('Error in optimizer: cannot find selectivity for '),
|
|
simplePred(P, PSimple), write(PSimple), nl,
|
|
write('Call: selectivity('), write(P), write(',Sel)\n'),
|
|
throw(error_Internal(statistics_selectivity(P, X)::selectivityQueryFailed)),
|
|
fail, !.
|
|
|
|
|
|
|
|
% Wrapper selectivity/5 to get also bbox selectivity
|
|
|
|
% faked predicate:
|
|
selectivity(pr(fakePred(Sel,BboxSel,CalcPET,ExpPET)),
|
|
Sel, BBoxSel, CalcPET, ExpPET) :-
|
|
( (ground(Sel), ground(BboxSel), ground(CalcPET), ground(ExpPET))
|
|
-> true
|
|
; throw(error_Internal(statistics_selectivity(
|
|
pr(fakePred(Sel,BboxSel,CalcPET,ExpPET)),
|
|
Sel, BBoxSel, CalcPET, ExpPET)
|
|
::fakePred_requires_ground_arguments))
|
|
),
|
|
!.
|
|
|
|
selectivity(Pred, Sel, BBoxSel, CalcPET, ExpPET) :-
|
|
selectivity(Pred, Sel, CalcPET, ExpPET),
|
|
simplePred(Pred, PSimple),
|
|
databaseName(DB),
|
|
( storedBBoxSel(DB, PSimple, BBoxSel)
|
|
; (commute(PSimple,PSimple2), storedBBoxSel(DB, PSimple2, BBoxSel) )
|
|
),
|
|
!.
|
|
|
|
selectivity(Pred, Sel, noBBox, CalcPET, ExpPET) :-
|
|
selectivity(Pred, Sel, CalcPET, ExpPET).
|
|
|
|
% selectivity/4
|
|
|
|
% faked predicate:
|
|
selectivity(pr(fakePred(Sel,BboxSel,CalcPET,ExpPET)), Sel, CalcPET, ExpPET) :-
|
|
( (ground(Sel), ground(BboxSel), ground(CalcPET), ground(ExpPET))
|
|
-> true
|
|
; throw(error_Internal(statistics_selectivity(
|
|
pr(fakePred(Sel,BboxSel,CalcPET,ExpPET)), Sel, CalcPET, ExpPET)
|
|
::fakePred_requires_ground_arguments))
|
|
),
|
|
!.
|
|
|
|
% handle 'pseudo-joins' (2 times the same argument) as selections
|
|
selectivity(pr(Pred, Rel, Rel), Sel, CalcPET, ExpPET) :-
|
|
selectivity(pr(Pred, Rel), Sel, CalcPET, ExpPET), !.
|
|
|
|
% check if selectivity has already been stored
|
|
selectivity(P, Sel, CalcPET, ExpPET) :-
|
|
simplePred(P, PSimple),
|
|
sels(PSimple, Sel, CalcPET, ExpPET), !.
|
|
|
|
/*
|
|
NVK ADDED NR
|
|
|
|
*/
|
|
selectivity(pr(Pred, Rel1, Rel2), Sel, CalcPET, ExpPET) :-
|
|
optimizerOption(nestedRelations),
|
|
nrSelectivity(pr(Pred, Rel1, Rel2), Sel, CalcPET, ExpPET),
|
|
!.
|
|
|
|
selectivity(pr(Pred, Rel), Sel, CalcPET, ExpPET) :-
|
|
optimizerOption(nestedRelations),
|
|
nrSelectivity(pr(Pred, Rel), Sel, CalcPET, ExpPET),
|
|
!.
|
|
% NVK ADDED NR END
|
|
|
|
% query for join-selectivity (static samples case)
|
|
selectivity(pr(Pred, Rel1, Rel2), Sel, CalcPET, ExpPET) :-
|
|
not(optimizerOption(dynamicSample)),
|
|
Rel1 = rel(BaseName1, _),
|
|
ensureSampleJexists(BaseName1),
|
|
Rel2 = rel(BaseName2, _),
|
|
ensureSampleJexists(BaseName2),
|
|
selectivityQueryJoin(Pred, Rel1, Rel2, MSs, BBoxResCard,
|
|
FilterInputCard, ResCard, InputCard),
|
|
nonzero(ResCard, NonzeroResCard),
|
|
nonzero(InputCard, NonzeroInputCard),
|
|
nonzero(FilterInputCard, NonzeroFilterInputCard),
|
|
Sel is NonzeroResCard / NonzeroInputCard, % must not be 0
|
|
|
|
( BBoxResCard = noBBox
|
|
-> ExpPET is MSs / NonzeroInputCard
|
|
; ExpPET is MSs / NonzeroFilterInputCard
|
|
),
|
|
|
|
simplePred(pr(Pred, Rel1, Rel2), PSimple),
|
|
predCost(PSimple, CalcPET), % calculated PET
|
|
|
|
dm(selectivity,['Predicate Cost : (', CalcPET, '/', ExpPET,
|
|
') ms\nSelectivity : ', Sel,'\n']),
|
|
databaseName(DB),
|
|
assert(storedPET(DB, PSimple, CalcPET, ExpPET)),
|
|
assert(storedSel(DB, PSimple, Sel)),
|
|
( ( BBoxResCard = noBBox ; storedBBoxSel(DB, PSimple, _) )
|
|
-> true
|
|
; ( nonzero(BBoxResCard, NonzeroBBoxResCard),
|
|
BBoxSel is NonzeroBBoxResCard / NonzeroInputCard,
|
|
dm(selectivity,['BBox-Selectivity: ',BBoxSel,'\n']),
|
|
assert(storedBBoxSel(DB, PSimple, BBoxSel))
|
|
)
|
|
),
|
|
( optimizerOption(determinePredSig)
|
|
-> (
|
|
getTypeTree(Pred, [(1,Rel1),(2,Rel2)], [Op,Args,ResultType]),
|
|
extractSignature(Args,ArgTypeList),
|
|
Signature =.. [Op|ArgTypeList],
|
|
assert(storedPredicateSignature(DB, PSimple, [Op,Args,ResultType])),
|
|
dm(selectivity,['The topmost signature for ',Pred,' is:\t',
|
|
Signature,' -> ',ResultType,'\n'])
|
|
)
|
|
; true
|
|
),
|
|
!.
|
|
|
|
% query for selection-selectivity (static samples case)
|
|
selectivity(pr(Pred, Rel), Sel, CalcPET, ExpPET) :-
|
|
not(optimizerOption(dynamicSample)),
|
|
Rel = rel(BaseName, _),
|
|
ensureSampleSexists(BaseName),
|
|
selectivityQuerySelection(Pred, Rel, MSs, BBoxResCard, ResCard, InputCard),
|
|
nonzero(ResCard, NonzeroResCard),
|
|
nonzero(InputCard, NonzeroInputCard),
|
|
Sel is NonzeroResCard / NonzeroInputCard, % must not be 0
|
|
tupleSizeSplit(BaseName,TupleSize),
|
|
calcExpPET(MSs, NonzeroInputCard, TupleSize, MSsRes), % correct PET
|
|
simplePred(pr(Pred, Rel), PSimple),
|
|
predCost(PSimple,CalcPET), % calculated PET
|
|
ExpPET is MSsRes / max(NonzeroInputCard,1),
|
|
dm(selectivity,['Predicate Cost : (', CalcPET, '/', ExpPET,
|
|
') ms\nSelectivity : ', Sel,'\n']),
|
|
databaseName(DB),
|
|
assert(storedPET(DB, PSimple, CalcPET, ExpPET)),
|
|
assert(storedSel(DB, PSimple, Sel)),
|
|
( ( BBoxResCard = noBBox ; storedBBoxSel(DB, PSimple, _) )
|
|
-> true
|
|
; ( nonzero(BBoxResCard, NonzeroBBoxResCard),
|
|
BBoxSel is NonzeroBBoxResCard / NonzeroInputCard,
|
|
dm(selectivity,['BBox-Selectivity: ',BBoxSel,'\n']),
|
|
assert(storedBBoxSel(DB, PSimple, BBoxSel))
|
|
)
|
|
),
|
|
( optimizerOption(determinePredSig)
|
|
-> (
|
|
getTypeTree(Pred, [(1,Rel)], [Op,Args,ResultType]),
|
|
extractSignature(Args,ArgTypeList),
|
|
Signature =.. [Op|ArgTypeList],
|
|
assert(storedPredicateSignature(DB, PSimple, [Op,Args,ResultType])),
|
|
dm(selectivity,['The topmost signature for ',Pred,' is:\t',
|
|
Signature,' -> ',ResultType,'\n'])
|
|
)
|
|
; true
|
|
),
|
|
!.
|
|
|
|
% query for join-selectivity (dynamic sampling case)
|
|
selectivity(pr(Pred, Rel1, Rel2), Sel, CalcPET, ExpPET) :-
|
|
optimizerOption(dynamicSample),
|
|
selectivityQueryJoin(Pred, Rel1, Rel2, MSs, BBoxResCard,
|
|
FilterInputCard, ResCard, InputCard),
|
|
nonzero(ResCard, NonzeroResCard),
|
|
nonzero(InputCard, NonzeroInputCard),
|
|
nonzero(FilterInputCard, NonzeroFilterInputCard),
|
|
Sel is NonzeroResCard / NonzeroInputCard, % must not be 0
|
|
|
|
( BBoxResCard = noBBox
|
|
-> ExpPET is MSs / NonzeroInputCard
|
|
; ExpPET is MSs / NonzeroFilterInputCard
|
|
),
|
|
|
|
simplePred(pr(Pred, Rel1, Rel2), PSimple),
|
|
predCost(PSimple, CalcPET), % calculated PET
|
|
|
|
dm(selectivity,['Predicate Cost : (', CalcPET, '/', ExpPET,
|
|
') ms\nSelectivity : ', Sel,'\n']),
|
|
|
|
databaseName(DB),
|
|
assert(storedPET(DB, PSimple, CalcPET, ExpPET)),
|
|
assert(storedSel(DB, PSimple, Sel)),
|
|
( ( BBoxResCard = noBBox ; storedBBoxSel(DB, PSimple, _) )
|
|
-> true
|
|
; ( nonzero(BBoxResCard, NonzeroBBoxResCard),
|
|
BBoxSel is NonzeroBBoxResCard / NonzeroInputCard,
|
|
dm(selectivity,['BBox-Selectivity: ',BBoxSel,'\n']),
|
|
assert(storedBBoxSel(DB, PSimple, BBoxSel))
|
|
)
|
|
),
|
|
( optimizerOption(determinePredSig)
|
|
-> (
|
|
getTypeTree(Pred, [(1,Rel1),(2,Rel2)], [Op,Args,ResultType]),
|
|
extractSignature(Args,ArgTypeList),
|
|
Signature =.. [Op|ArgTypeList],
|
|
assert(storedPredicateSignature(DB, PSimple, [Op,Args,ResultType])),
|
|
dm(selectivity,['The topmost signature for ',Pred,' is:\t',
|
|
Signature,' -> ',ResultType,'\n'])
|
|
|
|
)
|
|
; true
|
|
),
|
|
!.
|
|
|
|
% query for selection-selectivity (dynamic sampling case)
|
|
selectivity(pr(Pred, Rel), Sel, CalcPET, ExpPET) :-
|
|
optimizerOption(dynamicSample),
|
|
Rel = rel(BaseName, _),
|
|
selectivityQuerySelection(Pred, Rel, MSs, BBoxResCard, ResCard, InputCard),
|
|
nonzero(ResCard, NonzeroResCard),
|
|
nonzero(InputCard, NonzeroInputCard),
|
|
Sel is NonzeroResCard / NonzeroInputCard, % must not be 0
|
|
tupleSizeSplit(BaseName,TupleSize),
|
|
calcExpPET(MSs, NonzeroInputCard, TupleSize, MSsRes), % correct PET
|
|
simplePred(pr(Pred, Rel), PSimple),
|
|
predCost(PSimple,CalcPET), % calculated PET
|
|
ExpPET is MSsRes / max(NonzeroInputCard,1),
|
|
dm(selectivity,['Predicate Cost : (', CalcPET, '/', ExpPET,
|
|
') ms\nSelectivity : ', Sel,'\n']),
|
|
databaseName(DB),
|
|
assert(storedPET(DB, PSimple, CalcPET, ExpPET)),
|
|
assert(storedSel(DB, PSimple, Sel)),
|
|
( ( BBoxResCard = noBBox ; storedBBoxSel(DB, PSimple, _) )
|
|
-> true
|
|
; ( nonzero(BBoxResCard, NonzeroBBoxResCard),
|
|
BBoxSel is NonzeroBBoxResCard / NonzeroInputCard,
|
|
dm(selectivity,['BBox-Selectivity: ',BBoxSel,'\n']),
|
|
assert(storedBBoxSel(DB, PSimple, BBoxSel))
|
|
)
|
|
),
|
|
( optimizerOption(determinePredSig)
|
|
-> (
|
|
getTypeTree(Pred, [(1,Rel)], [Op,Args,ResultType]),
|
|
extractSignature(Args,ArgTypeList),
|
|
Signature =.. [Op|ArgTypeList],
|
|
assert(storedPredicateSignature(DB, PSimple, [Op,Args,ResultType])),
|
|
dm(selectivity,['The topmost signature for ',Pred,' is:\t',
|
|
Signature,' -> ',ResultType,'\n'])
|
|
)
|
|
; true
|
|
),
|
|
!.
|
|
|
|
% handle ERRORs
|
|
selectivity(P, X, Y, Z) :-
|
|
simplePred(P, PSimple),
|
|
term_to_atom(PSimple,PSimpleT),
|
|
my_concat_atom(['Cannot find selectivity for \'', PSimpleT, '\'.'],'',ErrMsg),
|
|
write('Error in optimizer: '), write(ErrMsg),
|
|
write('Call: selectivity('), write(P), write(', _, _, _)\n'),
|
|
throw(error_Internal(statistics_selectivity(P, X, Y, Z)
|
|
::selectivityQueryFailed#ErrMsg)),
|
|
fail, !.
|
|
|
|
|
|
% access stored PETs by simplified predicate term
|
|
getPET(pr(fakePred(Sel,BboxSel,CalcPET,ExpPET)), CalcPET, ExpPET) :-
|
|
( (ground(Sel), ground(BboxSel), ground(CalcPET), ground(ExpPET))
|
|
-> true
|
|
; throw(error_Internal(statistics_simplePred(
|
|
pr(fakePred(Sel,BboxSel,CalcPET,ExpPET)),
|
|
fakePred(Sel,BboxSel,CalcPET,ExpPET))
|
|
::fakePred_requires_ground_arguments))
|
|
),
|
|
!.
|
|
|
|
getPET(P, CalcPET, ExpPET) :-
|
|
databaseName(DB),
|
|
simplePred(P,PSimple),
|
|
( storedPET(DB, PSimple, CalcPET, ExpPET)
|
|
; ( commute(PSimple, PSimple2), storedPET(DB, PSimple2, CalcPET, ExpPET) )
|
|
), !.
|
|
|
|
getPET(P, X, Y) :-
|
|
simplePred(P, PSimple),
|
|
term_to_atom(PSimple,PSimpleT),
|
|
my_concat_atom(['Cannot find PETs for \'', PSimpleT, '\'.'],'',ErrMsg),
|
|
write('Error in optimizer: '), write(ErrMsg), nl,
|
|
write('Call: getPET('), write(P), write(', _, _)\n'),
|
|
throw(error_Internal(statistics_getPET(P, X, Y)::missingData#ErrMsg)),
|
|
fail, !.
|
|
|
|
|
|
getBBoxSel(pr(fakePred(Sel,BBoxSel,CalcPET,ExpPET), BBoxSel)) :-
|
|
( (ground(Sel), ground(BBoxSel), ground(CalcPET), ground(ExpPET))
|
|
-> true
|
|
; throw(error_Internal(statistics_getBBoxSel(
|
|
pr(fakePred(Sel,BBoxSel,CalcPET,ExpPET)),
|
|
BBoxSel)::fakePred_requires_ground_arguments))
|
|
),
|
|
!.
|
|
|
|
getBBoxSel(Pred,BBoxSel) :-
|
|
simplePred(Pred, PSimple),
|
|
databaseName(DB),
|
|
storedBBoxSel(DB, PSimple, BBoxSel).
|
|
|
|
|
|
/*
|
|
|
|
The selectivities retrieved via Secondo queries can be loaded
|
|
(by calling ~readStoredSels~) and stored (by calling
|
|
~writeStoredSels~).
|
|
|
|
*/
|
|
|
|
readStoredSels :-
|
|
retractall(storedSel(_, _, _)),
|
|
retractall(storedBBoxSel(_, _, _)),
|
|
retractall(storedPredicateSignature(_, _, _)),
|
|
retractall(storedBBoxSize(_,_,_)),
|
|
% [storedSels].
|
|
load_storefiles(storedSels).
|
|
|
|
/*
|
|
|
|
The following functions are auxiliary functions for ~writeStoredSels~. Their
|
|
purpose is to convert ~string~ and ~text~ values into a "save" format in order
|
|
to write it to a file, that can be parsed by the Prolog system without e.g.
|
|
mismatching a capital starting letter with a Prolog variable.
|
|
Therefor, strings should be (1) converted from list of
|
|
character codes (e.g. [100, 99, 100]) to an atom (e.g. "dcd"), which makes the
|
|
stored selectitivities more readable. (2) the string atom should be written as
|
|
a quoted literal.
|
|
|
|
----
|
|
replaceCharList(+In,?Out)
|
|
isIntList(+T)
|
|
charListToAtom(+CL,?Atom)
|
|
----
|
|
is deprecated. It was used to avoid character code lists within output.
|
|
|
|
However, correct handling of string and text atoms - including proper
|
|
quoting - can be ensured using built-in predicates writeq/1, writeq/2, and
|
|
format option ~q~ within predicates format/2 and format/3.
|
|
|
|
*/
|
|
|
|
isIntList([]) :- !.
|
|
|
|
isIntList([X | Rest]) :-
|
|
integer(X),
|
|
isIntList(Rest), !.
|
|
|
|
charListToAtom(CharList, Atom) :-
|
|
atom_codes(A, CharList),
|
|
my_concat_atom([' "', A, '"'], Atom).
|
|
|
|
%handle string values in order to avoid problems with starting capital letters
|
|
replaceCharList(value_expr(string,InString), value_expr(string,OutString)) :-
|
|
term_string(InString,OutString), !.
|
|
replaceCharList([const,Value,string], [const,Value2,string]) :-
|
|
term_string(Value,Value2), !.
|
|
|
|
%handle text values in order to avoid problems with starting capital letters
|
|
replaceCharList(value_expr(text,InText), value_expr(text,OutString)) :-
|
|
term_string(InText,OutString),
|
|
!.
|
|
replaceCharList([const,Value,text], [const,Value2,text]) :-
|
|
term_string(Value,Value2),
|
|
!.
|
|
|
|
%handle old string representation
|
|
replaceCharList(InTerm, OutTerm) :-
|
|
isIntList(InTerm), !,
|
|
charListToAtom(InTerm, OutTerm), !.
|
|
|
|
replaceCharList(InTerm, OutTerm) :-
|
|
compound(InTerm),
|
|
\+ is_list(InTerm),
|
|
!,
|
|
InTerm =.. TermAsList,
|
|
maplist(replaceCharList, TermAsList, OutTermAsList),
|
|
OutTerm =.. OutTermAsList, !.
|
|
|
|
replaceCharList(X, X) :- !.
|
|
|
|
writeStoredSels :-
|
|
open('storedSels.pl', write, FD),
|
|
write(FD,
|
|
'/* Automatically generated file, do not edit by hand. */\n'),
|
|
findall(_, writeStoredSel(FD), _),
|
|
close(FD).
|
|
|
|
writeStoredSel(Stream) :-
|
|
storedSel(DB, X, Y),
|
|
%replaceCharList(X, XReplaced),
|
|
writeq(Stream, storedSel(DB, X, Y)), write(Stream, '.\n').
|
|
|
|
writeStoredSel(Stream) :-
|
|
storedBBoxSel(DB, X, Y),
|
|
%replaceCharList(X, XReplaced),
|
|
writeq(Stream, storedBBoxSel(DB, X, Y)), write(Stream, '.\n').
|
|
|
|
writeStoredSel(Stream) :-
|
|
storedPredicateSignature(DB, X, Y),
|
|
%replaceCharList(X, XR),
|
|
writeq(Stream, storedPredicateSignature(DB, X, Y)),
|
|
write(Stream, '.\n').
|
|
|
|
writeStoredSel(Stream) :-
|
|
storedBBoxSize(DB,X,Y),
|
|
%replaceCharList(X, XReplaced),
|
|
writeq(Stream, storedBBoxSize(DB, X, Y)),
|
|
write(Stream, '.\n').
|
|
|
|
showSel :-
|
|
storedSel(DB, X, Y),
|
|
%replaceCharList(X, XRepl),
|
|
format(' ~w~16|~w.~q~n',[Y,DB,X]).
|
|
|
|
showBBoxSel :-
|
|
storedBBoxSel(DB, X, Y),
|
|
%replaceCharList(X, XRepl),
|
|
format(' ~w~16|~w.~q~n',[Y,DB,X]).
|
|
|
|
showBBoxSize :-
|
|
storedBBoxSize(DB, X, Y),
|
|
%replaceCharList(X, XRepl),
|
|
format(' ~w~16|~w.~q~n',[Y,DB,X]).
|
|
|
|
:-assert(helpLine(showSels,0,[],'Display known selectivities.')).
|
|
showSels :-
|
|
write('\nStored selectivities:\n'),
|
|
findall(_, showSel, _),
|
|
write('\nStored bbox-selectivities:\n'),
|
|
findall(_, showBBoxSel, _),
|
|
write('\nStored average bbox sizes:\n'),
|
|
findall(_, showBBoxSize, _).
|
|
|
|
:-
|
|
dynamic(storedSel/3),
|
|
dynamic(storedBBoxSel/3),
|
|
dynamic(storedPredicateSignature/3),
|
|
dynamic(storedBBoxSize/3),
|
|
at_halt(writeStoredSels),
|
|
readStoredSels.
|
|
|
|
readStoredPETs :-
|
|
retractall(storedPET(_, _, _, _)),
|
|
% [storedPETs].
|
|
load_storefiles(storedPETs).
|
|
|
|
writeStoredPETs :-
|
|
open('storedPETs.pl', write, FD),
|
|
write(FD,
|
|
'/* Automatically generated file, do not edit by hand. */\n'),
|
|
findall(_, writeStoredPET(FD), _),
|
|
close(FD).
|
|
|
|
writeStoredPET(Stream) :-
|
|
storedPET(DB, X, Y, Z),
|
|
replaceCharList(X, XReplaced),
|
|
write(Stream, storedPET(DB, XReplaced, Y, Z)), write(Stream, '.\n').
|
|
|
|
:-assert(helpLine(showPETs,0,[],'Display known predicate evaluation times.')).
|
|
showPETs :-
|
|
write('\nStored predicate costs:\n'),
|
|
format(' ~w~18|~w~34|~w~n',['Calculated [ms]', 'Measured [ms]','Predicate']),
|
|
findall(_, showPET, _).
|
|
|
|
showPET :-
|
|
storedPET(DB, P, Calc, Exp),
|
|
%replaceCharList(P, PRepl),
|
|
format(' ~w~18|~w~34|~w.~q~n',[Calc, Exp, DB, P]).
|
|
|
|
:-
|
|
dynamic(storedPET/4),
|
|
at_halt(writeStoredPETs),
|
|
readStoredPETs.
|
|
|
|
writePETs :-
|
|
findall(_, writePET, _).
|
|
|
|
writePET :-
|
|
storedPET(DB, X, Y, Z),
|
|
%replaceCharList(X, XReplaced),
|
|
write('DB: '), write(DB),
|
|
write(', Predicate: '), writeq(X),
|
|
write(', Cost: '), write(Y), write('/'), write(Z), write(' ms\n').
|
|
|
|
|
|
readStoredPredicateSignatures :-
|
|
retractall(storedPredicateSignature(_, _, _)),
|
|
% [storedPredicateSignatures].
|
|
load_storefiles(storedPredicateSignatures).
|
|
|
|
writeStoredPredicateSignatures :-
|
|
open('storedPredicateSignatures.pl', write, FD),
|
|
write(FD,
|
|
'/* Automatically generated file, do not edit by hand. */\n'),
|
|
findall(_, writeStoredPredicateSignature(FD), _),
|
|
close(FD).
|
|
|
|
writeStoredPredicateSignature(Stream) :-
|
|
storedPredicateSignature(DB, X, Y),
|
|
%replaceCharList(X, XR),
|
|
writeq(Stream, storedPredicateSignature(DB, X, Y)),
|
|
write(Stream, '.\n').
|
|
|
|
:-assert(helpLine(showStoredPredicateSignatures,0,[],
|
|
'Display known predicate signatures.')).
|
|
showStoredPredicateSignatures :-
|
|
write('\nStored predicate signatures:\n'),
|
|
format(' ~w~12|~w~36|~w~n',['Database','Predicate','Signature']),
|
|
findall(_, showStoredPredicateSignature, _).
|
|
|
|
showStoredPredicateSignature :-
|
|
storedPredicateSignature(DB, P, S),
|
|
format(' ~w~12|~q~36|~q~n',[DB, P, S]).
|
|
|
|
|
|
/*
|
|
1.5 Determining System Speed and Calibration Factors
|
|
|
|
To achieve good cost estimations, the used cost factors for operators need to
|
|
be calibrated.
|
|
|
|
*/
|
|
|
|
/*
|
|
The cost factors for the cost functions are read from a file:
|
|
|
|
*/
|
|
|
|
readStoredOperatorTF :-
|
|
retractall(tempOperatorTF(_)),
|
|
retractall(storedOperatorTF(_)),
|
|
% [sysDependentOperatorTF].
|
|
load_storefiles(sysDependentOperatorTF).
|
|
|
|
|
|
/*
|
|
The cost factors for the cost functions are stored into a file;
|
|
|
|
*/
|
|
|
|
writeStoredOperatorTF :-
|
|
open('sysDependentOperatorTF.pl', write, FD),
|
|
write(FD, '/* Automatically generated file, do not edit by hand. */\n'),
|
|
findall(_, writeStoredOperatorTF(FD), _),
|
|
close(FD).
|
|
|
|
writeStoredOperatorTF(Stream) :-
|
|
storedOperatorTF(Op, A, B),
|
|
write(Stream, storedOperatorTF(Op, A, B)),
|
|
write(Stream, '.\n').
|
|
|
|
/*
|
|
The Original cost factors for operators are:
|
|
|
|
*/
|
|
setOriginalOperatorTFs :-
|
|
assert(storedOperatorTF(consume, 0.00000147, 0.0003)),
|
|
assert(storedOperatorTF(loopjoin, 0.000000095, 0.000014)),
|
|
assert(storedOperatorTF(filter, 0, 0)),
|
|
assert(storedOperatorTF(string, notype, 0.00000053)),
|
|
assert(storedOperatorTF(int, notype, 0.00000051)),
|
|
assert(storedOperatorTF(real, notype, 0.00000052)),
|
|
assert(storedOperatorTF(feed, 0.000000735, 0)),
|
|
assert(storedOperatorTF(producta, 0.00000781, 0.00453249)),
|
|
assert(storedOperatorTF(productb, 0.000049807, 0.008334)),
|
|
assert(storedOperatorTF(productc, 0.434782, 0)),
|
|
assert(storedOperatorTF(hashtemp, 0.000000789, 0.0002168)),
|
|
assert(storedOperatorTF(hashcachecal, 0.1, 61.2)),
|
|
assert(storedOperatorTF(hashtab, 0.000000766, 0)),
|
|
assert(storedOperatorTF(extend, 0.000015, 0)),
|
|
assert(storedOperatorTF(intsort, 0.000000083, 0.00001086)),
|
|
assert(storedOperatorTF(extsort, 0.000000218, 0.000125193)),
|
|
assert(storedOperatorTF(concatenationjoin, 0.000000095, 0.000014)),
|
|
assert(storedOperatorTF(concatenationflob, 0.00000171, 0)),
|
|
assert(storedOperatorTF(spatialjoinx, 0.000000216, 0.00000000004)),
|
|
assert(storedOperatorTF(spatialjoiny, 0.00000024, 0.000000000045)),
|
|
assert(storedOperatorTF(remove, 0.000015, 0)),
|
|
assert(storedOperatorTF(rename, 0.00001, 0)),
|
|
assert(storedOperatorTF(project, 0, 0)),
|
|
assert(storedOperatorTF(count, 0, 0)),
|
|
assert(storedOperatorTF(orderby, 0, 0)),
|
|
assert(storedOperatorTF(groupby, 0, 0)),
|
|
assert(storedOperatorTF(exactmatchfun, 0.000002265, 0.000298)),
|
|
assert(storedOperatorTF(exactmatch, 0.000002265, 0.000298)),
|
|
assert(storedOperatorTF(leftrange, 0.000002265, 0.000298)),
|
|
assert(storedOperatorTF(windowintersects, 0.000000972, 0)),
|
|
assert(storedOperatorTF(insidelr, 0.016712944, 0)).
|
|
|
|
:- dynamic(storedOperatorTF/3),
|
|
at_halt(writeStoredOperatorTF),
|
|
readStoredOperatorTF.
|
|
|
|
:- ( not(storedOperatorTF(_,_,_))
|
|
-> setOriginalOperatorTFs
|
|
; true
|
|
).
|
|
|
|
|
|
/*
|
|
Estimate the speed the stytem by posing a specific query, calculating the used
|
|
time and comparing it with the value of the appropriate cost function. From
|
|
this, calculate a new calibration factor.
|
|
|
|
*/
|
|
|
|
tfCPU(TestRel) :-
|
|
my_concat_atom(['query ', TestRel, ' feed count'],'',Query),
|
|
getTime(secondo(Query, [_, _]),Time),
|
|
downcase_atom(TestRel, DCTestRel),
|
|
write('\n>>>>>>>stat_012\n'), nl,
|
|
card(DCTestRel, Card),
|
|
tupleSizeSplit(DCTestRel, sizeTerm(Core, InFlob, _)),
|
|
TLExt is Core + InFlob,
|
|
testRelVolume(Card, TLExt),
|
|
storedOperatorTF(feed, A, B),
|
|
Cost is (TLExt * A + B) * Card,
|
|
CFnew is Time / (Cost * 1000),
|
|
vCostFactorCPU(V),
|
|
nl, write(' The current CPU calibration factor: '), write(V),
|
|
nl, write(' The suitable factor: '), write(CFnew),
|
|
setCostFactor(tempCostFactor(vCostFactorCPU,CFnew)).
|
|
|
|
testRelVolume(Size, TupleSizeExt) :-
|
|
Volume is Size * TupleSizeExt,
|
|
Volume > 3500000,
|
|
!.
|
|
|
|
testRelVolume(_, _) :-
|
|
nl,
|
|
write('Test relation should have a size of at least 3,5 MB (without Flobs).'),
|
|
fail.
|
|
|
|
|
|
/*
|
|
Create a new clause for the temporary storage of the new calibration factor.
|
|
|
|
*/
|
|
|
|
setCostFactor(tempCostFactor(Op, CF)) :-
|
|
retract(tempCostFactor(Op, _)),
|
|
assert(tempCostFactor(Op, CF)), !.
|
|
|
|
setCostFactor(tempCostFactor(Op, CF)) :-
|
|
assert(tempCostFactor(Op, CF)).
|
|
|
|
/*
|
|
Replaces the old calibration factor with a new one.
|
|
|
|
*/
|
|
|
|
updateCostFactorCPU :-
|
|
tempCostFactor(vCostFactorCPU, CF),
|
|
retract(vCostFactorCPU(_)),
|
|
assert(vCostFactorCPU(CF)),
|
|
write('vCostFactorCPU: '), write(CF),
|
|
write(' update').
|
|
|
|
updateCostFactorCPU(CF) :-
|
|
retract(vCostFactorCPU(_)),
|
|
assert(vCostFactorCPU(CF)),
|
|
write('vCostFactorCPU: '), write(CF),
|
|
write(' update').
|
|
|
|
/*
|
|
The calibration factor and the conversion factor for the cost functions
|
|
are read from a file ``costFactors.pl:
|
|
|
|
*/
|
|
|
|
readStoredCostFactors :-
|
|
retractall(wCostFactor(_)),
|
|
retractall(vCostFactorCPU(_)),
|
|
retractall(tempCostFactor(_,_)),
|
|
% [sysDependentCostFactors].
|
|
load_storefiles(sysDependentCostFactors).
|
|
|
|
writeStoredCostFactors :-
|
|
open('sysDependentCostFactors.pl', write, FD),
|
|
write(FD, '/* Automatically generated file, do not edit by hand. */\n'),
|
|
findall(_, writeStoredCostFactors(FD), _),
|
|
close(FD).
|
|
|
|
/*
|
|
The conversion factor for the cost functions is written back into the file.
|
|
|
|
*/
|
|
|
|
writeStoredCostFactors(Stream) :-
|
|
wCostFactor(X),
|
|
% replaceCharList(X, XReplaced),
|
|
write(Stream, wCostFactor(X)),
|
|
write(Stream, '.\n').
|
|
|
|
/*
|
|
The calibration factor of the cost functions is written back into the file.
|
|
|
|
*/
|
|
|
|
writeStoredCostFactors(Stream) :-
|
|
vCostFactorCPU(X),
|
|
% replaceCharList(X, XReplaced),
|
|
write(Stream, vCostFactorCPU(X)),
|
|
write(Stream, '.\n').
|
|
|
|
setOriginalCalibrationFactors :-
|
|
assert(wCostFactor(1000000)),
|
|
assert(vCostFactorCPU(1)).
|
|
|
|
|
|
:-
|
|
dynamic(costFactors/1),
|
|
at_halt(writeStoredCostFactors),
|
|
readStoredCostFactors.
|
|
|
|
:- ( (not(wCostFactor(_)) ; not(vCostFactorCPU(_)))
|
|
-> ( retractall(wCostFactor(_)),
|
|
retractall(vCostFactorCPU(_)),
|
|
retractall(tempCostFactor(_,_)),
|
|
setOriginalCalibrationFactors
|
|
)
|
|
; true
|
|
).
|
|
|
|
/*
|
|
1.6 Estimating PETs using an Analytical Model
|
|
|
|
---- predCost(+Pred, -PredCost)
|
|
predCost(+Predicate, -PredCost, -ArgTypeX, -ArgSize, +predArg(PA))
|
|
----
|
|
|
|
Calculation of the costs of a predicate. To get the total costs of a predicate,
|
|
the costs of its sub-terms are assessed first. The estimated costs are based
|
|
on the attribute sizes and the attribute types.
|
|
|
|
If the type of a term cannot be dertermined, a failure value (e.g. ~undefined~)
|
|
should be returned. The clauses should be modified to handle the case where a
|
|
recursive call yields an undefined result.
|
|
|
|
*/
|
|
|
|
predCost(Pred, PredCost) :-
|
|
predCost(Pred, PredCost, _, _, predArg(1)).
|
|
|
|
|
|
% Section:Start:predCost_5_b
|
|
% Section:End:predCost_5_b
|
|
|
|
predCost(Pred, PredCost, predArg(N)) :-
|
|
predCost(Pred, PredCost, _, _, predArg(N)).
|
|
|
|
predCost(X = Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
equalTCnew(ArgTypeX, ArgTypeY, OperatorTC),
|
|
% should somehow depend on ArgSize
|
|
PredCost is PredCostX + PredCostY + OperatorTC.
|
|
|
|
predCost(X < Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
smallerTCnew(ArgTypeX, ArgTypeY, OperatorTC),
|
|
PredCost is PredCostX + PredCostY + OperatorTC.
|
|
|
|
predCost(X > Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
biggerTCnew(ArgTypeX, ArgTypeY, OperatorTC),
|
|
PredCost is PredCostX + PredCostY + OperatorTC.
|
|
|
|
predCost(X <= Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
equalsmallerTCnew(ArgTypeX, ArgTypeY, OperatorTC),
|
|
PredCost is PredCostX + PredCostY + OperatorTC.
|
|
|
|
predCost(X >= Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
equalbiggerTCnew(ArgTypeX, ArgTypeY, OperatorTC),
|
|
PredCost is PredCostX + PredCostY + OperatorTC.
|
|
|
|
predCost(X inside Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
insideTCnew(ArgTypeX, ArgTypeY, OperatorTC, S),
|
|
sTTS(ArgSizeX,ArgSizeXT),
|
|
sTTS(ArgSizeY,ArgSizeYT),
|
|
PredCost is PredCostX + PredCostY
|
|
+ (ArgSizeXT ** S) * (ArgSizeYT * OperatorTC ) / 100000.
|
|
|
|
predCost(X adjacent Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
adjacentTCnew(ArgTypeX, ArgTypeY, OperatorTC, S),
|
|
sTTS(ArgSizeX,ArgSizeXT),
|
|
sTTS(ArgSizeY,ArgSizeYT),
|
|
PredCost is PredCostX + PredCostY
|
|
+ (ArgSizeXT * OperatorTC) * (ArgSizeYT ** S) / 100000.
|
|
|
|
predCost(X intersects Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
intersectsTCnew(ArgTypeX, ArgTypeY, OperatorTC, S),
|
|
sTTS(ArgSizeX,ArgSizeXT),
|
|
sTTS(ArgSizeY,ArgSizeYT),
|
|
PredCost is PredCostX + PredCostY
|
|
+ (ArgSizeXT * OperatorTC)*(ArgSizeYT ** S) / 100000.
|
|
|
|
predCost(X contains Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
containsTCnew(ArgTypeX, ArgTypeY, OperatorTC),
|
|
PredCost is PredCostX + PredCostY + OperatorTC.
|
|
|
|
predCost(X + Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
plusTCnew(ArgTypeX, ArgTypeY, OperatorTC),
|
|
PredCost is PredCostX + PredCostY + PA * OperatorTC.
|
|
|
|
predCost(X - Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
minusTCnew(ArgTypeX, ArgTypeY, OperatorTC),
|
|
PredCost is PredCostX + PredCostY + PA * OperatorTC.
|
|
|
|
predCost(X * Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
timesTCnew(ArgTypeX, ArgTypeY, OperatorTC),
|
|
PredCost is PredCostX + PredCostY + PA * OperatorTC.
|
|
|
|
predCost(X / Y, PredCost, ArgTypeX, ArgSize, predArg(PA)) :- !,
|
|
predCost(X, PredCostX, ArgTypeX, ArgSizeX, predArg(PA)),
|
|
predCost(Y, PredCostY, ArgTypeY, ArgSizeY, predArg(PA)),
|
|
biggerArg(ArgSizeX, ArgSizeY, ArgSize),
|
|
overTCnew(ArgTypeX, ArgTypeY, OperatorTC),
|
|
PredCost is PredCostX + PredCostY + PA * OperatorTC.
|
|
|
|
predCost(Rel:Attr, 0, ArgType, ArgSize, _) :- !,
|
|
downcase_atom(Attr, DCAttr),
|
|
downcase_atom(Rel, DCRel),
|
|
attrType(DCRel:DCAttr, ArgType),
|
|
attrSize(DCRel:DCAttr, ArgSize), !.
|
|
|
|
% Section:Start:predCost_5_m
|
|
% Section:End:predCost_5_m
|
|
|
|
% default value changed from 0 to 0.0000005
|
|
predCost(_, 0.0000005, notype, 1, _) :- !.
|
|
|
|
biggerArg(sizeTerm(X1,X2,X3), sizeTerm(Y1,Y2,Y3), sizeTerm(X1,X2,X3)) :-
|
|
X1+X2+X3 >= Y1+Y2+Y3, !.
|
|
|
|
biggerArg(_, Arg2, Arg2).
|
|
|
|
/*
|
|
~sTTS~ meams sizeTerm to Total Size.
|
|
|
|
Maps a sizeTerm to a single value, equal to the sum of the term's components.
|
|
|
|
*/
|
|
sTTS(sizeTerm(X,Y,Z),T) :-
|
|
T is X + Y + Z.
|
|
|
|
sTTS(T,T).
|
|
|
|
|
|
/*
|
|
Different operators can occur within a predicate. Cost factors for certain
|
|
predicates and different combinations of argument types are stored in the
|
|
following Prolog facts:
|
|
|
|
*/
|
|
|
|
plusTCnew(_, _, 0.0000005).
|
|
minusTCnew(_, _, 0.0000005).
|
|
smallerTCnew(_, _, 0.0000005).
|
|
biggerTCnew(_, _, 0.0000005).
|
|
timesTCnew(_, _, 0.0000005).
|
|
overTCnew(_, _, 0.0000005).
|
|
modTCnew(_, _, 0.0000005).
|
|
divTCnew(_, _, 0.0000005).
|
|
equalTCnew(_, _, 0.0000005).
|
|
equalbiggerTCnew(_, _, 0.0000005).
|
|
equalsmallerTCnew(_, _, 0.0000005).
|
|
insideTCnew(point, line, 0.05086, 0).
|
|
insideTCnew(point, region, 0.04457463, 0).
|
|
insideTCnew(line, region, 0.046230259, 0).
|
|
insideTCnew(region, region, 0.00004444, 1).
|
|
insideTCnew(_, _, 0.046230259, 0).
|
|
adjacentTCnew(line, region, 0.000004702, 1).
|
|
adjacentTCnew(region, line, 0.000004702, 1).
|
|
adjacentTCnew(region, region, 0.046612378, 0).
|
|
adjacentTCnew(line, line, 0.051482479, 0).
|
|
adjacentTCnew(_, _, 0.000040983, 0).
|
|
intersectsTCnew(line, line, 0.041509433, 0).
|
|
intersectsTCnew(line, region, 0.000046277, 0).
|
|
intersectsTCnew(region, line, 0.000046277, 0).
|
|
intersectsTCnew(region, region, 0.046612328, 0).
|
|
intersectsTCnew(_, _, 0.000046277, 0).
|
|
containsTCnew(_, _, 0.00002).
|
|
|
|
|
|
|
|
/*
|
|
1.7 Correcting Measured PETs
|
|
|
|
When ~optimizerOption(nawracosts))~ is defined, PETs will be corrected:
|
|
|
|
----
|
|
calcExpPET(+MSs, +InputCard, +TupleSize, -Time)
|
|
calcExpPET(+MSs, +InputCard, +TupleSize1, +TupleSize2, +ResCard, -Time)
|
|
----
|
|
Calculation of experimental net-PETs (predicate evaluation times):
|
|
|
|
Reduce the measured time ~MSs~ when determinating the selectivity of selection-
|
|
predicates
|
|
by the estimated costs of operator feed.
|
|
|
|
Reduce the measured time when determining the selectivity of join-predicates
|
|
by the estimated costs of the operators feed and loopjoin.
|
|
|
|
Other arguments: ~InputCard~ is the product of the cardinalities of the input
|
|
streams; ~TupleSize~, ~TupleSize1~, ~TupleSize2~ are the tuple sizes of the
|
|
input streams, ~ResCard~ is the cardinality of the join.
|
|
|
|
~Time~ is the sesulting net-PET in milliseconds.
|
|
|
|
*/
|
|
|
|
|
|
calcExpPET(MSs, Card, TupleSize, Time) :-
|
|
optimizerOption(nawracosts),
|
|
storedOperatorTF(feed, OpA, OpB),
|
|
wCostFactor(W),
|
|
TupleSize = sizeTerm(Core, InFlob, _),
|
|
Cost is (OpA * (Core + InFlob) + OpB) * Card,
|
|
costtotal(Cost, CostTotal),
|
|
TimeOp is MSs - (CostTotal / W) * 1000,
|
|
notnegativ(TimeOp, Time), !.
|
|
|
|
calcExpPET(MSs, _, _, MSs) :-
|
|
not(optimizerOption(nawracosts)), !.
|
|
|
|
calcExpPET(MSs, InputCard, TupleSize1, TupleSize2, ResCard, Time) :-
|
|
Card1 is sqrt(InputCard),
|
|
Card2 = Card1,
|
|
optimizerOption(nawracosts),
|
|
storedOperatorTF(feed, OpA, OpB),
|
|
storedOperatorTF(loopjoin, A, B),
|
|
storedOperatorTF(concatenationflob, A2, _),
|
|
TupleSize1 = sizeTerm(Core1, InFlob1, ExtFlob1),
|
|
TupleSize2 = sizeTerm(Core2, InFlob2, ExtFlob2),
|
|
FlobSize is ExtFlob1 + ExtFlob2,
|
|
ExtSize1 is Core1 + InFlob1,
|
|
ExtSize2 is Core2 + InFlob2,
|
|
wCostFactor(W),
|
|
Cost is (OpA * ExtSize1 + OpB) * Card1 + (OpA * ExtSize2 + OpB) * Card2
|
|
+ (((ExtSize1 + ExtSize2) * A + B) + (FlobSize * A2)) * ResCard,
|
|
costtotal(Cost, CostTotal),
|
|
TimeOp is MSs - (CostTotal / W) * 1000,
|
|
notnegativ(TimeOp, Time), !.
|
|
|
|
calcExpPET(MSs, _, _, _, _, MSs) :-
|
|
not(optimizerOption(nawracosts)), !.
|
|
|
|
|
|
/*
|
|
1 Determining Expression Types and Operator Signatures
|
|
|
|
The following predicates are used to determine the Signature of operators
|
|
used within queries, especially within predicates.
|
|
|
|
The approach investigates a term bottom-up, i.e. it first tries to determine
|
|
the type of the arguments on the leaves of the operator tree by inspecting the
|
|
attribute table or by sending ~getTypeNL~ or ~matchingOperators~ Queries to
|
|
Secondo.
|
|
|
|
Once all argument types are known for a operator node, we check whether the
|
|
signature is already known. If so, we already know the operator result type.
|
|
Otherwise, we need to query Secondo for it.
|
|
|
|
|
|
----
|
|
getTypeTree(+Expr,+RelList,-TypeTree)
|
|
getTypeTree(+Expr,-Result)
|
|
|
|
----
|
|
|
|
These predicates never fail, but throw exceptions instead!
|
|
|
|
Retrieve the complete type/operator tree ~TypeTree~ from an expression ~Expr~
|
|
for a given relation list ~RelList~. ~RelList~ may also contain
|
|
~type variable definitions~.
|
|
|
|
~Expr~ is an expression in internal format using attribute and relations
|
|
descriptors etc.
|
|
|
|
~RelList~ has format [(Arg1,Rel1),...(ArgN,RelN)], where Arg1...ArgN are
|
|
integers corresponding to the ~Arg~ fields used in attribute descriptors within
|
|
~Expr~, and Rel1,..., RelN are the according relation descriptors.
|
|
|
|
Additionally, ~RelList~ may contain type variable definitions. These have format
|
|
(typevar,TypeVarName,TypeList), where ~TypeVarName~ is a type variable name and
|
|
TypeList is the according type descriptor. A tuple variable is referenced by
|
|
using the expression ~typevar(TypeVarName)~ or --- within attribute descriptors
|
|
--- in place of the ~ArgNo~ field of attr/3 attribute descriptors:
|
|
~attr(AttrName, TypeVarName, Spell)~.
|
|
This is implemented to support type mapping for operators using parameter
|
|
functions.
|
|
|
|
For the variant ~getTypeTree/2~, see below.
|
|
|
|
~TypeTree~ has format [~Op~, ~TypeTreeList~, ~ResType~], where
|
|
~Op~ is the operator symbol,
|
|
~TypeTreeList~ is a list of entries with format ~TypeTree~, and
|
|
~ResType~ is the type of the complete expression (root node).
|
|
|
|
Atomic leaves have special markers instead of an operator symbol:
|
|
integer, real, text and string atoms have ~atom~, attributes have ~attr~,
|
|
constants ~constant~, attribute names have ~attrname~, database object names
|
|
have ~dbobject~, type names have ~typename~, relations have ~relation~. In all
|
|
these cases, ~TypeTreeList~ becomes the expression forming the according
|
|
primitive.
|
|
Newly created (calculated) attributes are marked with ~newattr~.
|
|
|
|
Facts describing known operator signatures are defined in file ~operators.pl~.
|
|
They all have format
|
|
|
|
---- opSignature(+Operator, +Algebra, +ArgTypeList, -Resulttype, -Flags).
|
|
----
|
|
|
|
~Operator~ is the name of the operator (Prolog infix-operators are inclosed in
|
|
round parantheses)
|
|
|
|
~Algebra~ is the DC-name of the algebra defining the operator.
|
|
|
|
~ArgTypeList~ is a PROLOG list of terms representing the valid Secondo type
|
|
expressions for all arguments.
|
|
|
|
~Resulttype~ is a term representing a valid Secondo type expression.
|
|
|
|
~Flags~ is a list describing certain properties of the operators
|
|
|
|
If an operator/signature combination is unknown, the optimizer tries to create
|
|
and execute a query to determine the according result type. If a result is
|
|
achieved, it is temporarily stored to the optimizer's knowledge base using the
|
|
dynamic predicate
|
|
|
|
---- queriedOpSignature(Op,ArgTypes,TypeDC,Flags).
|
|
----
|
|
|
|
|
|
The type trees of all analysed expressions are kept within temporary facts
|
|
|
|
---- tmpStoredExprTypeTree(+P,(-Op, -TypeTreeList, -ResType))
|
|
----
|
|
|
|
These facts are not made persistent and will be lost whenever a new query is
|
|
started.
|
|
|
|
---- getTypeTree(+Expr,-TypeTree)
|
|
----
|
|
|
|
If this variant of the predicate receives one argument ~Expr~, that represents
|
|
one of the internal predicate representations: pr(P,A) or pr(P,A,B), it can
|
|
automatically create the ~RelList~ and call getTypeTree/3.
|
|
|
|
If ~Expr~ is not an internal predicate term, a ~RelList~ is created from the
|
|
tables created by callLookup. This is implemented by the auxiliary predicate
|
|
getAllUsedRelations/1.
|
|
|
|
*/
|
|
:- dynamic(queriedOpSignature/4).% used for new operator signatures
|
|
:- dynamic(tmpStoredTypeTree/2). % used to buffer results of expression analysis
|
|
|
|
getTypeTree(PredExpr,Result) :-
|
|
PredExpr =.. [pr,P|RelList],
|
|
createRelArgListFromPredRelList(RelList,RelArgList),
|
|
getTypeTree(P,RelArgList,Result), !.
|
|
|
|
% createRelArgListFromPredRelList(+RelList,-RelArgList)
|
|
% numbers all elemenets from ~RelList~, starting with 1.
|
|
createRelArgListFromPredRelList(X,XA) :-
|
|
createRelArgListFromPredRelList2(X,1,XA),!.
|
|
createRelArgListFromPredRelList([],_,[]).
|
|
createRelArgListFromPredRelList([X|Xs],N1,[(N1,X)|X2]) :-
|
|
N2 is N1 + 1,
|
|
createRelArgListFromPredRelList(Xs,N2,X2).
|
|
|
|
|
|
% fail, if option not selected:
|
|
getTypeTree(_,_,_) :-
|
|
not(optimizerOption(determinePredSig)),!,
|
|
fail.
|
|
|
|
% getTypeTree(Expr,Rels,Result) :-
|
|
% write_list(['$$$ Calling ',getTypeTree(Expr,Rels,Result),'\n']),
|
|
% fail.
|
|
|
|
% Use temporarily saved results.
|
|
% Results of calls to getTypeTree/3 are saved as facts tmpStoredTypeTree/2
|
|
% for the time of the time until the optimizer is shut down or onother database
|
|
% is openend.
|
|
getTypeTree(Expr,_,Result) :-
|
|
tmpStoredTypeTree(Expr,Result),!.
|
|
|
|
% Handle Lists of expressions
|
|
getTypeTree(arglist([]),_,[]) :- !.
|
|
getTypeTree(arglist([X]),Rels,[X1]) :-
|
|
is_list(X),
|
|
catch((my_string_to_list(_,X), Test = ok),_,Test = failed), Test = failed,
|
|
%write('--------arglist([X])'- arglist([X])),nl,
|
|
getTypeTree(arglist(X),Rels,X1), !.
|
|
|
|
getTypeTree(arglist([X]),Rels,[X1]) :-
|
|
% not(is_list(X)),
|
|
getTypeTree(X,Rels,X1), !.
|
|
|
|
getTypeTree(arglist([X|R]),Rels,[X1|R1]) :-
|
|
is_list(X),
|
|
catch((my_string_to_list(_,X), Test = ok),_,Test = failed), Test = failed,
|
|
%write('--------arglist([X|R])'- arglist([X|R])),nl,
|
|
getTypeTree(arglist(X),Rels,X1),
|
|
getTypeTree(arglist(R),Rels,R1),
|
|
% dm(selectivity,['$$$ getTypeTree: []: []']),nl,
|
|
!.
|
|
|
|
getTypeTree(arglist([X|R]),Rels,[X1|R1]) :-
|
|
getTypeTree(X,Rels,X1),
|
|
getTypeTree(arglist(R),Rels,R1),
|
|
% dm(selectivity,['$$$ getTypeTree: []: []']),nl,
|
|
!.
|
|
|
|
% Special case: pseudo attribute 'rowid'
|
|
getTypeTree(rowid,_,[rowid,rowid,tid]) :-
|
|
assert(tmpStoredTypeTree(rowid,[rowid,rowid,tid])),
|
|
!.
|
|
|
|
% Primitive: int-atom (old style)
|
|
getTypeTree(IntAtom,_,[atom,IntAtom,int]) :-
|
|
atomic(IntAtom), integer(IntAtom),
|
|
% dm(selectivity,['$$$ getTypeTree: ',IntAtom,': ',int]),nl,
|
|
dm(gettypetree,['WARNING:\tUsing old constant rule for int-atom!\n']),
|
|
assert(tmpStoredTypeTree(IntAtom,[atom,IntAtom,int])),
|
|
!.
|
|
|
|
% Primitive: real-atom (old style)
|
|
getTypeTree(RealAtom,_,[atom,RealAtom,real]) :-
|
|
atomic(RealAtom), float(RealAtom),
|
|
% dm(selectivity,['$$$ getTypeTree: ',RealAtom,': ',real]),nl,
|
|
dm(gettypetree,['WARNING:\tUsing old constant rule for real-atom!\n']),
|
|
assert(tmpStoredTypeTree(RealAtom,[atom,RealAtom,real])),
|
|
!.
|
|
|
|
% Primitive: text-atom (old style)
|
|
getTypeTree(TextAtom,_,[atom,TextAtom,text]) :-
|
|
atom(TextAtom),
|
|
not(is_list(TextAtom)),
|
|
not(opSignature(TextAtom,_,[],_,_)),
|
|
% dm(selectivity,['$$$ getTypeTree: ',TextAtom,': ',text]),nl,
|
|
dm(gettypetree,['WARNING:\tUsing old constant rule for text-atom!\n']),
|
|
assert(tmpStoredTypeTree(TextAtom,[atom,TextAtom,text])),
|
|
!.
|
|
|
|
% Primitive: string-atom (old style)
|
|
getTypeTree(TextAtom,_,[atom,TextAtom,string]) :-
|
|
is_list(TextAtom), TextAtom = [First | _], atomic(First), !,
|
|
my_string_to_list(_,TextAtom),
|
|
% dm(selectivity,['$$$ getTypeTree: ',TextAtom,': ',string]),nl,
|
|
dm(gettypetree,['WARNING:\tUsing old constant rule for string-atom!\n']),
|
|
assert(tmpStoredTypeTree(TextAtom,[atom,TextAtom,string])),
|
|
!.
|
|
|
|
% Primitive: type-descriptor (old style)
|
|
getTypeTree(DCType,_,[typename,DCType,DCType]) :-
|
|
secDatatype(DCType, _, _, _, _, _),
|
|
% dm(selectivity,['$$$ getTypeTree: ',DCType,': ',DCType]),nl,
|
|
dm(gettypetree,['WARNING:\tUsing old rule for type-descriptor!\n']),
|
|
assert(tmpStoredTypeTree(DCType,[typename,DCType,DCType])),
|
|
!.
|
|
|
|
% Primitive: type-descriptor (new style)
|
|
getTypeTree(type_expr(Type),_,[typename,Type,Type]) :-
|
|
( atom(Type)
|
|
-> TypeConstructor = Type
|
|
; ( (compound(Type) , \+ is_list(Type) )
|
|
-> Type =.. [ TypeConstructor | _ ]
|
|
; fail
|
|
)
|
|
),
|
|
secDatatype(TypeConstructor, _, _, _, _, _),
|
|
dm(gettypetree,['$$$ getTypeTree: ',type_expr(Type),': ',
|
|
TypeConstructor,'\n']),
|
|
assert(tmpStoredTypeTree(type_expr(Type),[typename,Type,Type])),
|
|
!.
|
|
|
|
% Primitive: text constant value expression (new style)
|
|
getTypeTree(value_expr(text,Value),_,[constant,Value,text]) :-
|
|
ground(Value),
|
|
dm(gettypetree,['$$$ getTypeTree: ',value_expr(text,Value),': ',
|
|
text, ' - ', constant, '\n']),
|
|
assert(tmpStoredTypeTree(value_expr(text,Value),[constant,Value,text])),
|
|
!.
|
|
|
|
% Primitive: constant value expression (new style)
|
|
getTypeTree(value_expr(Type,Value),_,[constant,Value,Type]) :-
|
|
ground(Value),
|
|
dm(gettypetree,['$$$ getTypeTree: ',value_expr(Type,Value),': ',
|
|
Type, ' - ', constant,'\n']),
|
|
assert(tmpStoredTypeTree(value_expr(Type,Value),[constant,Value,Type])),
|
|
!.
|
|
|
|
% Primitive: relation-descriptor
|
|
getTypeTree(rel(DCrelName, X),_,[relation,rel(DCrelName, X),tuple(TupleList)]):-
|
|
getRelAttrList(DCrelName, AttrList, _),
|
|
findall((N,A),(member([N,A,_],AttrList)),TupleList),
|
|
% dm(selectivity,['$$$ getTypeTree: ',rel(DCrelName, X),': ',tuple(TupleList)]),
|
|
% nl,
|
|
assert(tmpStoredTypeTree(rel(DCrelName, X),
|
|
[relation,rel(DCrelName, X),tuple(TupleList)])),
|
|
!.
|
|
|
|
% Primitive: object-descriptor
|
|
getTypeTree(dbobject(NameDC),_,[dbobject,dbobject(NameDC),TypeDC]) :-
|
|
secondoCatalogInfo(NameDC,_,_,[TypeExprList]),
|
|
dcNList(TypeExprList,TypeDC),
|
|
% dm(selectivity,['$$$ getTypeTree: ',dbobject(NameDC),': ',TypeDC]),nl,
|
|
assert(tmpStoredTypeTree(dbobject(NameDC),
|
|
[dbobject,dbobject(NameDC),TypeDC])),
|
|
!.
|
|
|
|
% Primitive: attribute-descriptor
|
|
getTypeTree(attr(RenRelName:Attr, Arg, Z),RelList,
|
|
[attr,attr(RenRelName:Attr, Arg, Z),DCType]) :-
|
|
memberchk((Arg,Rel),RelList),
|
|
Rel = rel(DCrelName,RenRelName),
|
|
downcase_atom(Attr,DCAttr),
|
|
databaseName(DB),
|
|
storedRel(DB,DCrelName,AttrList),
|
|
memberchk(DCAttr,AttrList),
|
|
storedAttrSize(DB,DCrelName,DCAttr,DCType,_,_,_),
|
|
% dm(selectivity,['$$$ getTypeTree: ',attr(RenRelName:Attr, Arg, Z),
|
|
% ': ',DCType]),nl,
|
|
assert(tmpStoredTypeTree(attr(RenRelName:Attr, Arg, Z),
|
|
[attr,attr(RenRelName:Attr, Arg, Z),DCType])),
|
|
!.
|
|
|
|
getTypeTree(attr(Attr, Arg, Y),Rels,[attr,attr(Attr, Arg, Y),DCType]) :-
|
|
downcase_atom(Attr,DCAttr),
|
|
memberchk((Arg,Rel),Rels),
|
|
Rel = rel(DCrelName, _),
|
|
databaseName(DB),
|
|
storedRel(DB,DCrelName,AttrList),
|
|
memberchk(DCAttr,AttrList),
|
|
storedAttrSize(DB,DCrelName,DCAttr,DCType,_,_,_),
|
|
% dm(selectivity,['$$$ getTypeTree: ',attr(Attr, Arg, Y),': ',DCType]),nl,
|
|
assert(tmpStoredTypeTree(attr(Attr, Arg, Y),
|
|
[attr,attr(Attr, Arg, Y),DCType])),
|
|
!.
|
|
|
|
% Primitive: renamed attribute (user level syntax)
|
|
getTypeTree(RenRelName:Attr,RelList,
|
|
[attr,attr(RenRelName:Attr, Arg, Z),DCType]) :-
|
|
memberchk((Arg,Rel),RelList),
|
|
Rel = rel(DCrelName,RenRelName),
|
|
downcase_atom(Attr,DCAttr),
|
|
databaseName(DB),
|
|
storedRel(DB,DCrelName,AttrList),
|
|
memberchk(DCAttr,AttrList),
|
|
storedAttrSize(DB,DCrelName,DCAttr,DCType,_,_,_),
|
|
storedSpell(DB,DCrelName:DCAttr,AttrSpelled),
|
|
( compound(AttrSpelled) -> Z = l ; Z = u ),
|
|
% dm(selectivity,['$$$ getTypeTree: ',attr(RenRelName:Attr, Arg, Z),
|
|
% ': ',DCType]),nl,
|
|
assert(tmpStoredTypeTree(RenRelName:Attr,
|
|
[attr,attr(RenRelName:Attr, Arg, Z),DCType])),
|
|
!.
|
|
|
|
% Primitive: non renamed attribute (user level syntax)
|
|
getTypeTree(Attr,Rels,[attr,attr(Attr, Arg, Y),DCType]) :-
|
|
downcase_atom(Attr,DCAttr),
|
|
memberchk((Arg,Rel),Rels),
|
|
Rel = rel(DCrelName, _),
|
|
databaseName(DB),
|
|
storedRel(DB,DCrelName,AttrList),
|
|
memberchk(DCAttr,AttrList),
|
|
storedAttrSize(DB,DCrelName,DCAttr,DCType,_,_,_),
|
|
storedSpell(DB,DCrelName:DCAttr,AttrSpelled),
|
|
( compound(AttrSpelled) -> Y = l ; Y = u ),
|
|
% dm(selectivity,['$$$ getTypeTree: ',attr(Attr, Arg, Y),': ',DCType]),nl,
|
|
assert(tmpStoredTypeTree(DCrelName:Attr,
|
|
[attr,attr(Attr, Arg, Y),DCType])),
|
|
!.
|
|
|
|
% Primitive: attribute-name-descriptor
|
|
getTypeTree(attrname(attr(X:Name, Y, Z)),_,[attrname,
|
|
attrname(attr(X:Name, Y, Z)),DCType]) :-
|
|
downcase_atom(Name,DCType),
|
|
% dm(selectivity,['$$$ getTypeTree: ',attrname(attr(X:Name, Y, Z)),
|
|
% ': ',DCType]),nl,
|
|
assert(tmpStoredTypeTree(attrname(attr(X:Name, Y, Z)),_,[attrname,
|
|
attrname(attr(X:Name, Y, Z)),DCType])),
|
|
!.
|
|
getTypeTree(attrname(attr(Name, Y, Z)),_,[attrname,
|
|
attrname(attr(Name, Y, Z)),DCType]) :-
|
|
downcase_atom(Name,DCType),
|
|
% dm(selectivity,['$$$ getTypeTree: ',attrname(attr(Name, Y, Z)),
|
|
% ': ',DCType]),nl,
|
|
assert(tmpStoredTypeTree(attrname(attr(Name, Y, Z)),_,[attrname,
|
|
attrname(attr(Name, Y, Z)),DCType])),
|
|
!.
|
|
|
|
% Primitive: newly created attribute
|
|
getTypeTree(newattr(AttrExpr,ValExpr),Rels,[newattr,
|
|
[AttrExprTree,ValExprTree],DCType]) :-
|
|
getTypeTree(arglist([AttrExpr,ValExpr]),Rels,[AttrExprTree,ValExprTree]),
|
|
ValExprTree = [_,_,DCType],
|
|
% dm(selectivity,['$$$ getTypeTree: ',newattr(AttrExpr,ValExpr),
|
|
% ': ',DCType]),nl,
|
|
assert(tmpStoredTypeTree(newattr(AttrExpr,ValExpr),Rels,
|
|
[newattr,[AttrExprTree,ValExprTree],DCType])),
|
|
% also store the new attribue itself:
|
|
( AttrExpr = attrname(attr(Name, Arg, Case))
|
|
-> assert(tmpStoredTypeTree(attr(Name, Arg, Case),
|
|
[attr,attr(Name, Arg, Case),DCType]))
|
|
; true
|
|
), !.
|
|
|
|
% Expression is a null-ary operator using a defined operator signature
|
|
% Needs special treatment since PROLOG does not allow for empty parameter lists
|
|
getTypeTree(Op,_Rels,[Op,[],TypeDC]) :-
|
|
atom(Op),
|
|
secondoOp(Op, prefix, 0),
|
|
systemIdentifier(Op, _),
|
|
( opSignature(Op,_,[],TypeDC,_)
|
|
; queriedOpSignature(Op,[],TypeDC,_)
|
|
),
|
|
assert(tmpStoredTypeTree(Op,[Op,[],TypeDC])),
|
|
!.
|
|
|
|
% Expression is a null-ary operator using unknown operator signature
|
|
% Needs special treatment since PROLOG does not allow for empty parameter lists
|
|
getTypeTree(Op,_Rels,[Op,[],TypeDC]) :-
|
|
atom(Op),
|
|
secondoOp(Op, prefix, 0),
|
|
systemIdentifier(Op, _),
|
|
( \+(optimizerOption(use_matchingOperators))
|
|
-> ( % Alternative I: using operator 'getTypeNL'
|
|
createNullValues([],NullArgs),
|
|
% send getTypeNL-query to Secondo to infer the signature
|
|
NullQueryExpr =.. [Op|NullArgs],
|
|
plan_to_atom(getTypeNL(NullQueryExpr),NullQueryAtom),
|
|
my_concat_atom(['query ',NullQueryAtom],'',Query),
|
|
dm(selectivity,['getTypeNL-Query = ',Query]),nl,
|
|
secondo(Query,[text,TypeDC])
|
|
)
|
|
; ( % Alternative II: using operator 'matchingOperators'
|
|
|
|
my_concat_atom(['query matchingOperators() filter[.OperatorName="',Op,
|
|
'"] extract[ResultType]'],'',Query),
|
|
dm(selectivity,['matchingOperators-Query = ',Query]),nl,
|
|
secondo(Query,[text,TypeDC])
|
|
)
|
|
),
|
|
% store signature in fact base
|
|
assert(queriedOpSignature(Op,[],TypeDC,[])),
|
|
% dm(selectivity,['$$$ getTypeTree: ',Expr,': ',TypeDC]),nl,
|
|
assert(tmpStoredTypeTree(Op,[Op,[],TypeDC])),
|
|
!.
|
|
|
|
% Expression using defined operator signature
|
|
getTypeTree(Expr,Rels,[Op,ArgTree,TypeDC]) :-
|
|
compound(Expr),
|
|
not(is_list(Expr)),
|
|
Expr =.. [Op|Args],
|
|
Op \= (:), % this is not a valid operator!
|
|
getTypeTree(arglist(Args),Rels,ArgTree),
|
|
extractSignature(ArgTree,ArgTypes),
|
|
( opSignature(Op,_,ArgTypes,TypeDC,_)
|
|
; queriedOpSignature(Op,ArgTypes,TypeDC,_)
|
|
),
|
|
% dm(selectivity,['$$$ getTypeTree: ',Expr,': ',TypeDC]),nl,
|
|
assert(tmpStoredTypeTree(Expr,[Op,ArgTree,TypeDC])),
|
|
!.
|
|
|
|
% Expression using unknown operator signature
|
|
getTypeTree(Expr,Rels,[Op,ArgTree,TypeDC]) :-
|
|
compound(Expr),
|
|
not(is_list(Expr)),
|
|
Expr =.. [Op|Args],
|
|
Op \= (:), % this is not a valid operator!
|
|
getTypeTree(arglist(Args),Rels,ArgTree),
|
|
extractSignature(ArgTree,ArgTypes),
|
|
( \+(optimizerOption(use_matchingOperators))
|
|
-> ( % Alternative I: using operator 'getTypeNL'
|
|
extractSignature(ArgTree,ArgTypes),
|
|
%findall(T,member([_,_,T],ArgTree),ArgTypes),
|
|
% create a valid expression using defined null values
|
|
createNullValues(ArgTypes,NullArgs),
|
|
% send getTypeNL-query to Secondo to infer the signature
|
|
NullQueryExpr =.. [Op|NullArgs],
|
|
plan_to_atom(getTypeNL(NullQueryExpr),NullQueryAtom),
|
|
my_concat_atom(['query ',NullQueryAtom],'',Query),
|
|
dm(selectivity,['getTypeNL-Query = ',Query,'\n']),
|
|
secondo(Query,[text,TypeDC])
|
|
)
|
|
; ( % Alternative II: using operator 'matchingOperators'
|
|
extractSignature(ArgTree,ArgTypes),
|
|
%findall(T,member([_,_,T],ArgTree),ArgTypes),
|
|
my_concat_atom(ArgTypes, ', ', ArgTypesText),
|
|
my_concat_atom(['query matchingOperators( ',ArgTypesText,
|
|
' ) filter[.OperatorName="',Op,
|
|
'"] extract[ResultType]'],'',Query),
|
|
dm(selectivity,['matchingOperators-Query = ',Query,'\n']),
|
|
secondo(Query,[text,TypeDC])
|
|
)
|
|
),
|
|
dm(selectivity,['getTypeTree: TypeDC = ',TypeDC,'\n']),
|
|
% store signature in fact base
|
|
assert(queriedOpSignature(Op,ArgTypes,TypeDC,[])),
|
|
% dm(selectivity,['$$$ getTypeTree: ',Expr,': ',TypeDC]),nl,
|
|
assert(tmpStoredTypeTree(Expr,[Op,ArgTree,TypeDC])),
|
|
!.
|
|
|
|
getTypeTree(A,B,C) :-
|
|
term_to_atom(A,A1),
|
|
my_concat_atom(['Cannot resolve typetree for expression \'',A1,'\'.'],
|
|
'',MSG),
|
|
throw(error_Internal(statistics_getTypeTree(A,B,C)::typeMapError::MSG)),
|
|
!, fail.
|
|
|
|
/*
|
|
The following predicate changes a complete nested list to use DC-spelling
|
|
only.
|
|
|
|
---- dcNList(+NList,?DCNList)
|
|
----
|
|
|
|
*/
|
|
dcNList(X1,X2) :-
|
|
atomic(X1),
|
|
downcase_atom(X1,X2),!.
|
|
dcNList([],[]).
|
|
dcNList([X1|R1],[X2|R2]) :-
|
|
dcNList(X1,X2),
|
|
dcNList(R1,R2),!.
|
|
|
|
/*
|
|
Auxiliary predicate
|
|
|
|
----
|
|
(1) nestedTypeExpr2valueTypeExprAtom(+Type,-TypeAtom)
|
|
(2) valueTypeExpr2valueTypeExprAtom(+Type, -TypeAtom)
|
|
----
|
|
|
|
(1) transforms a type expression ~Type~ using square brackets and commas as
|
|
delimiters into an atom with the equivalent nested list representation using
|
|
round parantheses.
|
|
|
|
(2) transforms a type expression ~Type~ using round brackets and commas as
|
|
delimiters into an atom with the equivalent nested list representation using
|
|
round parantheses.
|
|
|
|
*/
|
|
|
|
|
|
nestedTypeExpr2valueTypeExprAtom([],'()') :- !.
|
|
|
|
nestedTypeExpr2valueTypeExprAtom(A,A) :-
|
|
atom(A), !.
|
|
|
|
nestedTypeExpr2valueTypeExprAtom(A,Result) :-
|
|
is_list(A),
|
|
nestedTypeExpr2valueTypeExprAtom_list(A,AAtom),
|
|
my_concat_atom(['(',AAtom,')'],'',Result), !.
|
|
|
|
nestedTypeExpr2valueTypeExprAtom(A,Result) :-
|
|
compound(A),
|
|
A =.. [TC|Arglist],
|
|
nestedTypeExpr2valueTypeExprAtom_list(Arglist,ArglistAtom),
|
|
my_concat_atom([TC,'(',ArglistAtom,')','',Result]), !.
|
|
|
|
nestedTypeExpr2valueTypeExprAtom_list([A|[]],AAtom) :-
|
|
nestedTypeExpr2valueTypeExprAtom(A,AAtom), !.
|
|
|
|
nestedTypeExpr2valueTypeExprAtom_list([A|B],Result) :-
|
|
nestedTypeExpr2valueTypeExprAtom(A,AAtom),
|
|
nestedTypeExpr2valueTypeExprAtom_list(B,BAtom),
|
|
my_concat_atom([AAtom,BAtom],', ',Result), !.
|
|
|
|
|
|
valueTypeExpr2valueTypeExprAtom(Term,Result) :-
|
|
term_to_atom(Term,TermAtom),
|
|
( (compound(Term), functor(Term,(,),_))
|
|
-> my_concat_atom(['(',TermAtom,')'],'',Result)
|
|
; Result = TermAtom
|
|
),
|
|
!.
|
|
|
|
/*
|
|
The following predicate extracts an operator's signature (a list of its
|
|
argument types) from its argument list, which is given as a list of ~TypeTree~s.
|
|
|
|
---- extractSignature(+TypeTreeList,-DataTypeList)
|
|
----
|
|
|
|
*/
|
|
extractSignature([],[]) :- !.
|
|
extractSignature([ArgsHead|ArgsRest],[TypesHead|TypesRest]) :-
|
|
extractSignatureElement(ArgsHead,TypesHead),
|
|
extractSignature(ArgsRest,TypesRest), !.
|
|
extractSignature(A,B) :-
|
|
throw(error_Internal(statistics_extractSignature(A,B)
|
|
::malformedTypeTreeList)),
|
|
!, fail.
|
|
|
|
extractSignatureElement([_, _, Type],Type) :- !.
|
|
extractSignatureElement(A,B) :-
|
|
throw(error_Internal(statistics_extractSignatureElement(A,B)
|
|
::nonMatchingTypeTreeListElement)),
|
|
!, fail.
|
|
|
|
/*
|
|
The next predicate creates a list of Null Values for a given type list.
|
|
For stream and relation arguments, typed but empty instances are returned.
|
|
For mappings, typed dummy mappings are created.
|
|
|
|
---- createNullValues(+Type,-Null)
|
|
----
|
|
|
|
~Type~ is a single type or a list of types.
|
|
|
|
~Null~ is the according Null Value, resp. a list of such NVs.
|
|
|
|
*/
|
|
% special case: indexes
|
|
createNullValues([tuple,_],_) :- fail.
|
|
createNullValues([rtree|_],_) :- fail.
|
|
createNullValues([rtree3|_],_) :- fail.
|
|
createNullValues([rtree3|_],_) :- fail.
|
|
|
|
% special case: relation types
|
|
createNullValues([RelType,[tuple,X]],NullRelString) :-
|
|
memberchk(RelType,[rel,trel]),
|
|
createConstAttrList(X,X1),
|
|
my_concat_atom(['[const ',RelType,'(tuple([',X1,'])) value ()]'],'',
|
|
NullRelAtom),
|
|
my_string_to_atom(NullRelString,NullRelAtom),!.
|
|
|
|
% special case: tuple streams
|
|
createNullValues([stream,[tuple,X]],feed(NullRelString)) :-
|
|
createConstAttrList(X,X1),
|
|
my_concat_atom(['[const ',rel,'(tuple([',X1,'])) value ()]'],'',NullRelAtom),
|
|
my_string_to_atom(NullRelString,NullRelAtom),!.
|
|
|
|
% special case: data streams
|
|
createNullValues([stream,T],feed(TNV)) :-
|
|
isData(T),
|
|
createNullValues(T,TNV),!.
|
|
|
|
% special case: parameter functions/ mappings
|
|
createNullValues([map|Args],fun(Params, ResNV)) :-
|
|
append(ArgTypeList,[ResType],Args),
|
|
createNullValues(ResType,ResNV),
|
|
createFunArgs(ArgTypeList,Params),!.
|
|
|
|
% handle lists
|
|
createNullValues([],[]).
|
|
createNullValues([X|R],[X1|R1]) :-
|
|
createNullValues(X,X1),
|
|
createNullValues(R,R1),!.
|
|
|
|
% handle single values
|
|
createNullValues(Type,NVstring) :-
|
|
( nullValue(Type,standard,NV) % try 'standard' value first
|
|
; nullValue(Type,empty,NV) % 'empty' value comes second
|
|
; nullValue(Type,_,NV) % any other NullValue as last resort
|
|
), !, % do not try again
|
|
my_concat_atom(['[const ',Type,' value ',NV,']'],'',NVatom),
|
|
my_string_to_atom(NVstring,NVatom),!.
|
|
|
|
% create an atom describing an attribute list
|
|
createConstAttrList([],'').
|
|
createConstAttrList([[Name,Type]],Expr) :-
|
|
my_concat_atom([Name,Type],':',Expr),!.
|
|
createConstAttrList([[Name,Type]|Rest],Expr) :-
|
|
Rest \= [],
|
|
my_concat_atom([Name,Type],':',Expr1),
|
|
createConstAttrList(Rest,Expr2),
|
|
my_concat_atom([Expr1,Expr2],',',Expr),!.
|
|
|
|
% create an argument list for a dummy function with given signature
|
|
% List format: [param(Var1, Type1), ..., param(VarN, TypeN)]
|
|
createFunArgs([],[]).
|
|
createFunArgs([ArgType|R],[param(Var, ArgType)|Args]) :-
|
|
newVariable(Var),
|
|
createFunArgs(R,Args),!.
|
|
|
|
|
|
/*
|
|
1 Printing Metadata on Database
|
|
|
|
---- showDatabase
|
|
----
|
|
|
|
This predicate will inquire all collected statistical data on the
|
|
opened Secondo database and print it on the screen.
|
|
|
|
*/
|
|
|
|
:-assert(helpLine(showDatabase,0,[],
|
|
'List available metadata on relations within current database.')).
|
|
|
|
showSingleOrdering(DB, Rel) :-
|
|
findall( X,
|
|
( storedOrder(DB,Rel,X1),
|
|
translateOrderingInfo(Rel, X1, X)
|
|
),
|
|
OrderingAttrs
|
|
),
|
|
write('\n\n\tOrdering: '),
|
|
write(OrderingAttrs), nl, !.
|
|
|
|
translateOrderingInfo(_, none,none) :- !.
|
|
translateOrderingInfo(_, shuffled,shuffled) :- !.
|
|
translateOrderingInfo(Rel, Attr, AttrS) :-
|
|
dcName2externalName(Rel:Attr, AttrS).
|
|
|
|
showSingleRelationCard(DB, Rel) :-
|
|
storedCard(DB, Rel, Card),
|
|
write('\n\n\tCardinality: '), write(Card), nl, !.
|
|
|
|
showSingleRelationCard(_, _) :-
|
|
write('\n\n\tCardinality: *'), nl, !.
|
|
|
|
showSingleRelationTuplesize(_, Rel) :-
|
|
tuplesize(Rel, Size),
|
|
tupleSizeSplit(Rel, Size2),
|
|
write('\tAvg.TupleSize: '), write(Size), write(' = '),
|
|
write(Size2), nl,
|
|
secOptConstant(tupleMemoryBaseSize, TBaseSize),
|
|
write('\t(Tuple size in memory is '), write(TBaseSize),
|
|
write(' + sum of attribute sizes.)'), nl,
|
|
!.
|
|
|
|
showSingleRelationTuplesize(_, _) :-
|
|
write('\tAvg.TupleSize: *'), nl, !.
|
|
|
|
showSingleIndex(Rel) :-
|
|
databaseName(DB),
|
|
storedIndex(DB, Rel, Attr, IndexType, _),
|
|
dcName2externalName(Rel:Attr, AttrS),
|
|
write('\t('), write(AttrS), write(':'), write(IndexType), write(')').
|
|
|
|
showSingleRelation :- showRelation(_).
|
|
:- assert(helpLine(showRelation,1,
|
|
[[+,'RelDC','The relation to get information about.']],
|
|
'Show meta data on a given relation.')).
|
|
|
|
showRelation(Rel) :-
|
|
databaseName(DB),
|
|
storedRel(DB, Rel, _),
|
|
dcName2externalName(Rel, RelS),
|
|
( ( sub_atom(Rel,_,_,1,'_sample_') ; sub_atom(Rel,_,_,0,'_small') )
|
|
-> fail
|
|
; true
|
|
),
|
|
write('\nRelation '), write(RelS),
|
|
( systemTable(Rel,_)
|
|
-> write('\t***SYSTEM TABLE***')
|
|
; true
|
|
),
|
|
getSampleSname(RelS, SampleS),
|
|
getSampleJname(RelS, SampleJ),
|
|
getSmallName(RelS, Small),
|
|
write('\t(Auxiliary objects:'),
|
|
( secondoCatalogInfo(DCSampleS,SampleS,_,_)
|
|
-> (card(DCSampleS,CardSS), write_list([' SelSample(',CardSS,') ']) )
|
|
; true ),
|
|
( secondoCatalogInfo(DCSampleJ,SampleJ,_,_)
|
|
-> (card(DCSampleJ,CardSJ), write_list([' JoinSample(',CardSJ,') ']) )
|
|
; true ),
|
|
( secondoCatalogInfo(DCSmall,Small ,_,_)
|
|
-> (card(DCSmall,CardSM), write_list([' SmallObject(',CardSM,') ']) )
|
|
; true ),
|
|
write(')'), nl,
|
|
findall(_, showAllAttributes(Rel), _),
|
|
findall(_, showAllIndices(Rel), _),
|
|
showSingleOrdering(DB, Rel),
|
|
showSingleRelationCard(DB, Rel),
|
|
showSingleRelationTuplesize(DB, Rel).
|
|
|
|
showSingleAttribute(Rel,Attr) :-
|
|
databaseName(DB),
|
|
storedAttrSize(DB, Rel, Attr, Type, MemSize, CoreSize, LobSize),
|
|
dcName2externalName(Rel:Attr, AttrS),
|
|
format('\t~w~35|~w~49|~w~60|~w~69|~w~n',
|
|
[AttrS, Type, MemSize, CoreSize, LobSize]).
|
|
|
|
showAllAttributes(Rel) :-
|
|
format('\t~w~35|~w~49|~w~57|~w~69|~w~n',
|
|
['AttributeName','Type','Memory','DiskCore','DiskLOB']),
|
|
findall(_, showSingleAttribute(Rel, _), _).
|
|
|
|
showAllIndices(Rel) :-
|
|
write('\n\tIndices: \n'),
|
|
findall(_, showSingleIndex(Rel), _).
|
|
|
|
showDatabase :-
|
|
databaseName(DB),
|
|
write('\nCollected information for database \''), write(DB),
|
|
write('\':\n'),
|
|
findall(_, showSingleRelation, _),
|
|
write('\n(Type \'showDatabaseSchema.\' to view the complete '),
|
|
write('database schema.)\n'),
|
|
!.
|
|
|
|
showDatabase :-
|
|
not(databaseName(_)),
|
|
write('\nNo database open. Use open \'database <name>\' to'),
|
|
write(' open an existing database.\n'),
|
|
fail.
|
|
|
|
/*
|
|
1 Examples
|
|
|
|
The following examples can be used used to test the functionality of this
|
|
module.
|
|
|
|
Example 22:
|
|
|
|
*/
|
|
example24 :- optimize(
|
|
select *
|
|
from [staedte as s, ten]
|
|
where [
|
|
s:plz < 1000 * no,
|
|
s:plz < 4578]
|
|
).
|
|
|
|
/*
|
|
Example 23:
|
|
|
|
*/
|
|
|
|
example23 :- optimize(
|
|
select *
|
|
from [thousand as th, ten]
|
|
where [
|
|
(th:no mod 10) < 5,
|
|
th:no * 100 < 50000,
|
|
(th:no mod 7) = no]
|
|
).
|
|
|
|
/*
|
|
End of file ~statistics.pl~
|
|
|
|
*/
|