mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 06:03:02 +01:00
More and better optimizations with "complex" JOIN queries (LEFT JOIN, views, sp etc...).
bugfix: An SORT can't be generated when there are already RSBs on the stack, because this will lead to strange values. See also SF BUG # [ 221921 ].
This commit is contained in:
parent
8cd30039aa
commit
fcb77779fa
@ -3905,9 +3905,14 @@ static void pass1_source(
|
||||
1) If the view has a projection, and the query rse already has a projection
|
||||
defined; there is probably some way to merge these projections and do them
|
||||
both at once, but for now we'll punt on that.
|
||||
2) If it's part of an outer join. */
|
||||
2) If it's part of an outer join.
|
||||
|
||||
AB: If the view has an projection we never expand it.
|
||||
Because this can create wierd PLANs with multiple views/tables/sp joins
|
||||
*/
|
||||
|
||||
if ((view_rse->rse_projection && rse->rse_projection)
|
||||
if ((view_rse->rse_projection)
|
||||
//if ((view_rse->rse_projection && rse->rse_projection)
|
||||
|| rse->rse_jointype) {
|
||||
node = copy(tdbb, csb, (JRD_NOD) view_rse, map, 0, FALSE);
|
||||
DEBUG;
|
||||
|
136
src/jrd/opt.cpp
136
src/jrd/opt.cpp
@ -304,9 +304,10 @@ RSB OPT_compile(TDBB tdbb,
|
||||
#ifndef STACK_REDUCTION
|
||||
UCHAR *p, *q, streams[MAX_STREAMS], beds[MAX_STREAMS],
|
||||
*k, *b_end, *k_end, key_streams[MAX_STREAMS],
|
||||
local_streams[MAX_STREAMS], used_streams[MAX_STREAMS];
|
||||
local_streams[MAX_STREAMS], outer_streams[MAX_STREAMS],
|
||||
sub_streams[MAX_STREAMS]
|
||||
#else
|
||||
UCHAR *local_streams, *used_streams;
|
||||
UCHAR *local_streams, *outer_streams, *sub_streams;
|
||||
UCHAR *p, *q, *streams, *beds, *k, *b_end, *k_end, *key_streams;
|
||||
#endif
|
||||
|
||||
@ -348,7 +349,9 @@ RSB OPT_compile(TDBB tdbb,
|
||||
(UCHAR *) ALLOC_LIB_MEMORY((DWORD) (sizeof(UCHAR) * MAX_STREAMS));
|
||||
local_streams =
|
||||
(UCHAR *) ALLOC_LIB_MEMORY((DWORD) (sizeof(UCHAR) * MAX_STREAMS));
|
||||
used_streams =
|
||||
outer_streams =
|
||||
(UCHAR *) ALLOC_LIB_MEMORY((DWORD) (sizeof(UCHAR) * MAX_STREAMS));
|
||||
sub_streams =
|
||||
(UCHAR *) ALLOC_LIB_MEMORY((DWORD) (sizeof(UCHAR) * MAX_STREAMS));
|
||||
opt_ = (OPT) ALLOC_LIB_MEMORY((DWORD) (sizeof(Opt)));
|
||||
if (streams == NULL || beds == NULL || key_streams == NULL ||
|
||||
@ -361,6 +364,10 @@ RSB OPT_compile(TDBB tdbb,
|
||||
FREE_LIB_MEMORY(beds);
|
||||
if (streams != NULL)
|
||||
FREE_LIB_MEMORY(streams);
|
||||
if (outer_streams != NULL)
|
||||
FREE_LIB_MEMORY(outer_streams);
|
||||
if (sub_streams != NULL)
|
||||
FREE_LIB_MEMORY(sub_streams);
|
||||
if (opt_ != NULL)
|
||||
FREE_LIB_MEMORY(opt_);
|
||||
ERR_post(isc_virmemexh, 0);
|
||||
@ -383,7 +390,7 @@ RSB OPT_compile(TDBB tdbb,
|
||||
if (rse->nod_flags & rse_stream)
|
||||
opt_->opt_g_flags |= opt_g_stream;
|
||||
|
||||
beds[0] = streams[0] = key_streams[0] = used_streams[0] = 0;
|
||||
beds[0] = streams[0] = key_streams[0] = outer_streams[0] = sub_streams[0] = 0;
|
||||
conjunct_stack = rivers_stack = NULL;
|
||||
conjunct_count = 0;
|
||||
|
||||
@ -459,15 +466,30 @@ RSB OPT_compile(TDBB tdbb,
|
||||
compute_dbkey_streams(csb, node, key_streams);
|
||||
/* pass rse boolean only to inner substreams because join condition
|
||||
should never exclude records from outer substreams */
|
||||
if ( rse->rse_jointype==blr_inner ||
|
||||
(rse->rse_jointype==blr_left && (ptr - rse->rse_relation)==1) ||
|
||||
(rse->rse_jointype==blr_right && (ptr - rse->rse_relation)==0) )
|
||||
if (rse->rse_jointype == blr_inner ||
|
||||
(rse->rse_jointype == blr_left && (ptr - rse->rse_relation)==1) ||
|
||||
(rse->rse_jointype == blr_right && (ptr - rse->rse_relation)==0) )
|
||||
{
|
||||
/* AB: For an (X LEFT JOIN Y) mark the outer-streams (X) as
|
||||
active because the inner-streams (Y) are always "dependent"
|
||||
on the outer-streams. So that index retrieval nodes could be made.
|
||||
For an INNER JOIN mark previous generated RSB's as active. */
|
||||
if (rse->rse_jointype == blr_left) {
|
||||
for (i = 1; i <= outer_streams[0]; i++) {
|
||||
csb->csb_rpt[outer_streams[i]].csb_flags |= csb_active;
|
||||
}
|
||||
}
|
||||
*stack_end = parent_stack;
|
||||
rsb = OPT_compile(tdbb, csb, (RSE) node, conjunct_stack);
|
||||
*stack_end = NULL;
|
||||
if (rse->rse_jointype == blr_left) {
|
||||
for (i = 1; i <= outer_streams[0]; i++) {
|
||||
csb->csb_rpt[outer_streams[i]].csb_flags &= ~csb_active;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rsb = OPT_compile(tdbb, csb, (RSE) node, parent_stack);
|
||||
find_used_streams(rsb, outer_streams);
|
||||
}
|
||||
}
|
||||
|
||||
@ -481,7 +503,13 @@ RSB OPT_compile(TDBB tdbb,
|
||||
river->riv_count = (UCHAR) i;
|
||||
river->riv_rsb = rsb;
|
||||
MOVE_FAST(local_streams + 1, river->riv_streams, i);
|
||||
find_used_streams(rsb, used_streams);
|
||||
/* AB: Save all inner-part streams */
|
||||
if (rse->rse_jointype == blr_inner ||
|
||||
(rse->rse_jointype == blr_left && (ptr - rse->rse_relation)==0) ||
|
||||
(rse->rse_jointype == blr_right && (ptr - rse->rse_relation)==1) )
|
||||
{
|
||||
find_used_streams(rsb, sub_streams);
|
||||
}
|
||||
set_made_river(opt_, river);
|
||||
set_inactive(opt_, river);
|
||||
LLS_PUSH(river, &rivers_stack);
|
||||
@ -495,6 +523,8 @@ RSB OPT_compile(TDBB tdbb,
|
||||
++streams[0];
|
||||
*p++ = (UCHAR) stream;
|
||||
|
||||
outer_streams[++outer_streams[0]] = stream;
|
||||
|
||||
/* if we have seen any booleans or sort fields, we may be able to
|
||||
use an index to optimize them; retrieve the current format of
|
||||
all indices at this time so we can determine if it's possible */
|
||||
@ -538,7 +568,27 @@ RSB OPT_compile(TDBB tdbb,
|
||||
ERR_post(isc_optimizer_blk_exc, 0);
|
||||
/* Msg442: size of optimizer block exceeded */
|
||||
|
||||
for (i = 0; i < conjunct_count; i++) {
|
||||
/* AB: Because know we're going to use both parent & conjunct_stack
|
||||
try to again to make additional conjuncts for an inner join,
|
||||
but be sure that opt_->opt_count contains the real "base" */
|
||||
for (stack_end = &conjunct_stack; *stack_end;
|
||||
stack_end = &(*stack_end)->lls_next);
|
||||
SLONG saved_conjunct_count = conjunct_count;
|
||||
*stack_end = parent_stack;
|
||||
conjunct_count += distribute_equalities(&conjunct_stack, csb);
|
||||
*stack_end = NULL;
|
||||
|
||||
if (conjunct_count > MAX_CONJUNCTS)
|
||||
ERR_post(isc_optimizer_blk_exc, 0);
|
||||
/* Msg442: size of optimizer block exceeded */
|
||||
|
||||
/* AB: If equality nodes could be made get them first from the stack */
|
||||
for (i = saved_conjunct_count; i < conjunct_count; i++) {
|
||||
opt_->opt_rpt[i].opt_conjunct = node = (JRD_NOD) LLS_POP(&conjunct_stack);
|
||||
compute_dependencies(node, opt_->opt_rpt[i].opt_dependencies);
|
||||
}
|
||||
|
||||
for (i = 0; i < saved_conjunct_count; i++) {
|
||||
opt_->opt_rpt[i].opt_conjunct = node = (JRD_NOD) LLS_POP(&conjunct_stack);
|
||||
compute_dependencies(node, opt_->opt_rpt[i].opt_dependencies);
|
||||
}
|
||||
@ -569,24 +619,31 @@ RSB OPT_compile(TDBB tdbb,
|
||||
else
|
||||
rse->rse_aggregate = aggregate = NULL;
|
||||
|
||||
/* AB: Mark the previous used streams (sub-rse's) as active */
|
||||
for (i = 1; i <= sub_streams[0]; i++) {
|
||||
csb->csb_rpt[sub_streams[i]].csb_flags |= csb_active;
|
||||
}
|
||||
|
||||
/* outer joins require some extra processing */
|
||||
|
||||
if (rse->rse_jointype != blr_inner)
|
||||
if (rse->rse_jointype != blr_inner) {
|
||||
rsb = gen_outer(tdbb, opt_, rse, rivers_stack, &sort, &project);
|
||||
}
|
||||
else {
|
||||
BOOLEAN sort_present;
|
||||
JRD_NOD saved_sort_node;
|
||||
RSB test_rsb;
|
||||
BOOLEAN sort_present = (sort) ? TRUE : FALSE;
|
||||
BOOLEAN outer_rivers = FALSE;
|
||||
JRD_NOD saved_sort_node = sort;
|
||||
|
||||
/* mark the previous used streams (sub-rse's) as active */
|
||||
|
||||
for (i = 1; i <= used_streams[0]; i++) {
|
||||
csb->csb_rpt[used_streams[i]].csb_flags |= csb_active;
|
||||
/* AB: If previous rsb's are already on the stack we can't use
|
||||
an navigational-retrieval for an ORDER BY cause the next
|
||||
streams are JOINed to the previous onces */
|
||||
if (rivers_stack) {
|
||||
sort = NULL;
|
||||
outer_rivers = TRUE;
|
||||
}
|
||||
|
||||
/* attempt to form joins in decreasing order of desirability */
|
||||
saved_sort_node = sort;
|
||||
sort_present = (sort) ? TRUE : FALSE;
|
||||
|
||||
gen_join(tdbb, opt_, streams, &rivers_stack, &sort, &project,
|
||||
rse->rse_plan);
|
||||
|
||||
@ -601,11 +658,12 @@ RSB OPT_compile(TDBB tdbb,
|
||||
an index doesn't guarantee that the result will be in that
|
||||
order. So we assigned the sort node back.
|
||||
SF BUG # [ 221921 ] ORDER BY has no effect */
|
||||
test_rsb = rsb;
|
||||
RSB test_rsb = rsb;
|
||||
if ((rsb) && (rsb->rsb_type == rsb_boolean) && (rsb->rsb_next)) {
|
||||
test_rsb = rsb->rsb_next;
|
||||
}
|
||||
if ((test_rsb) && (test_rsb->rsb_type == rsb_merge) && !sort && sort_present) {
|
||||
if ((sort_present && outer_rivers) ||
|
||||
((test_rsb) && (test_rsb->rsb_type == rsb_merge) && !sort && sort_present)) {
|
||||
sort = saved_sort_node;
|
||||
}
|
||||
|
||||
@ -687,7 +745,9 @@ RSB OPT_compile(TDBB tdbb,
|
||||
DEBUG
|
||||
/* free up memory for optimizer structures */
|
||||
#ifdef STACK_REDUCTION
|
||||
FREE_LIB_MEMORY(local_streams);
|
||||
FREE_LIB_MEMORY(sub_streams);
|
||||
FREE_LIB_MEMORY(outer_streams);
|
||||
FREE_LIB_MEMORY(local_streams);
|
||||
FREE_LIB_MEMORY(key_streams);
|
||||
FREE_LIB_MEMORY(beds);
|
||||
FREE_LIB_MEMORY(streams);
|
||||
@ -715,7 +775,8 @@ RSB OPT_compile(TDBB tdbb,
|
||||
csb->csb_rpt[stream].csb_idx_allocation = 0;
|
||||
}
|
||||
#ifdef STACK_REDUCTION
|
||||
FREE_LIB_MEMORY(used_streams);
|
||||
FREE_LIB_MEMORY(sub_streams);
|
||||
FREE_LIB_MEMORY(outer_streams);
|
||||
FREE_LIB_MEMORY(local_streams);
|
||||
FREE_LIB_MEMORY(key_streams);
|
||||
FREE_LIB_MEMORY(beds);
|
||||
@ -3005,28 +3066,29 @@ static void find_used_streams(RSB rsb, UCHAR * streams)
|
||||
|
||||
switch (rsb->rsb_type) {
|
||||
|
||||
case rsb_aggregate:
|
||||
case rsb_ext_indexed:
|
||||
case rsb_ext_sequential:
|
||||
case rsb_indexed:
|
||||
case rsb_navigate:
|
||||
case rsb_procedure:
|
||||
case rsb_sequential:
|
||||
case rsb_union:
|
||||
stream = rsb->rsb_stream;
|
||||
found = TRUE;
|
||||
break;
|
||||
|
||||
|
||||
case rsb_cross:
|
||||
for (ptr = rsb->rsb_arg, end = ptr + rsb->rsb_count; ptr < end; ptr++) {
|
||||
find_used_streams(*ptr, streams);
|
||||
}
|
||||
break;
|
||||
|
||||
case rsb_union:
|
||||
for (ptr = rsb->rsb_arg, end = ptr + rsb->rsb_count; ptr < end; ptr++) {
|
||||
find_used_streams(*ptr, streams);
|
||||
}
|
||||
break;
|
||||
|
||||
case rsb_merge:
|
||||
for (ptr = rsb->rsb_arg, end = ptr + rsb->rsb_count * 2; ptr < end; ptr += 2) {
|
||||
/*for (ptr = rsb->rsb_arg, end = ptr + rsb->rsb_count * 2; ptr < end; ptr += 2) {
|
||||
find_used_streams(*ptr, streams);
|
||||
}
|
||||
}*/
|
||||
// Nothing
|
||||
break;
|
||||
|
||||
case rsb_left_cross:
|
||||
@ -3034,16 +3096,6 @@ static void find_used_streams(RSB rsb, UCHAR * streams)
|
||||
find_used_streams(rsb->rsb_arg[RSB_LEFT_outer], streams);
|
||||
break;
|
||||
|
||||
case rsb_indexed:
|
||||
stream = rsb->rsb_stream;
|
||||
found = TRUE;
|
||||
break;
|
||||
|
||||
case rsb_sequential:
|
||||
stream = rsb->rsb_stream;
|
||||
found = TRUE;
|
||||
break;
|
||||
|
||||
default: /* Shut up compiler warnings */
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user