LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_optimizer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 104 114 91.2 %
Date: 2024-12-20 21:24:02 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * N. Nes, M.L. Kersten
      15             :  * The queries are stored in the user cache after they have been
      16             :  * type checked and optimized.
      17             :  */
      18             : #include "monetdb_config.h"
      19             : #include "mal_builder.h"
      20             : #include "sql_mvc.h"
      21             : #include "sql_optimizer.h"
      22             : #include "sql_scenario.h"
      23             : #include "sql_gencode.h"
      24             : #include "opt_pipes.h"
      25             : 
      26             : /* calculate the footprint for optimizer pipe line choices
      27             :  * and identify empty columns upfront for just in time optimizers.
      28             :  */
      29             : static lng
      30     1000019 : SQLgetColumnSize(sql_trans *tr, sql_column *c, int access)
      31             : {
      32     1000019 :         sqlstore *store = tr->store;
      33     2000038 :         return store->storage_api.count_col(tr, c, access);
      34             : }
      35             : 
      36             : static lng
      37        6467 : SQLgetIdxSize(sql_trans *tr, sql_idx *i, int access)
      38             : {
      39        6467 :         sqlstore *store = tr->store;
      40        6467 :         return store->storage_api.count_idx(tr, i, access);
      41             : }
      42             : 
      43             : 
      44             : /*
      45             :  * The maximal space occupied by a query is calculated
      46             :  * under the assumption that the complete database should fit in memory.
      47             :  * The assumption is that the plan does not contain duplicate bind operations.
      48             :  * Calculation of the precise footprint is much more complex
      49             :  * and can not deal with intermediate structures, or fast
      50             :  * access using sorted probing.
      51             :  *
      52             :  * A run where we only take the size of a table only once,
      53             :  * caused major degradation on SF100 Q3 with SSD(>6x)
      54             :  */
      55             : 
      56             : static lng
      57      570168 : SQLgetSpace(mvc *m, MalBlkPtr mb, int prepare)
      58             : {
      59      570168 :         sql_trans *tr = m->session->tr;
      60      570168 :         lng size,space = 0, i;
      61      570168 :         str lasttable = 0;
      62             : 
      63    14352591 :         for (i = 0; i < mb->stop; i++) {
      64    13782464 :                 InstrPtr p = mb->stmt[i];
      65             : 
      66             :                 /* now deal with the update binds, it is only necessary to identify that there are updates
      67             :                  * The actual size is not that important */
      68    13782464 :                 if (getModuleId(p) == sqlRef && getFunctionId(p) == bindRef  && p->retc <= 2){
      69     1000050 :                         char *sname = getVarConstant(mb, getArg(p, 1 + p->retc)).val.sval;
      70     1000050 :                         char *tname = getVarConstant(mb, getArg(p, 2 + p->retc)).val.sval;
      71     1000050 :                         char *cname = getVarConstant(mb, getArg(p, 3 + p->retc)).val.sval;
      72     1000050 :                         int access = getVarConstant(mb, getArg(p, 4 + p->retc)).val.ival;
      73     1000050 :                         sql_schema *s = mvc_bind_schema(m, sname);
      74     1000059 :                         sql_table *t = 0;
      75     1000059 :                         sql_column *c = 0;
      76             : 
      77     1000059 :                         if (!s)
      78           0 :                                 continue;
      79     1000059 :                         t = mvc_bind_table(m, s, tname);
      80     1000051 :                         if (!t || isDeclaredTable(t))
      81           0 :                                 continue;
      82     1000051 :                         c = mvc_bind_column(m, t, cname);
      83     1000008 :                         if (!c)
      84           0 :                                 continue;
      85             : 
      86             :                         /* we have to sum the cost of all three components of a BAT */
      87     1000008 :                         if (c && isTable(c->t) && (lasttable == 0 || strcmp(lasttable,tname)==0)) {
      88     1000019 :                                 size = SQLgetColumnSize(tr, c, access);
      89     1000019 :                                 space += size;  // accumulate once per table
      90             :                                 //lasttable = tname;     invalidate this attempt
      91     1000019 :                                 if( !prepare && size == 0  && ! t->system){
      92      286396 :                                         setFunctionId(p, emptybindRef);
      93             :                                 }
      94             :                         }
      95             :                 }
      96    13782423 :                 if (getModuleId(p) == sqlRef && (getFunctionId(p) == bindidxRef)) {
      97        6467 :                         char *sname = getVarConstant(mb, getArg(p, 1 + p->retc)).val.sval;
      98             :                         //char *tname = getVarConstant(mb, getArg(p, 2 + p->retc)).val.sval;
      99        6467 :                         char *idxname = getVarConstant(mb, getArg(p, 3 + p->retc)).val.sval;
     100        6467 :                         int access = getVarConstant(mb, getArg(p, 4 + p->retc)).val.ival;
     101        6467 :                         sql_schema *s = mvc_bind_schema(m, sname);
     102             : 
     103        6467 :                         if (getFunctionId(p) == bindidxRef) {
     104        6467 :                                 sql_idx *i = mvc_bind_idx(m, s, idxname);
     105             : 
     106        6467 :                                 if (i && isTable(i->t)) {
     107        6467 :                                         size = SQLgetIdxSize(tr, i, access);
     108             : 
     109        6467 :                                         if( !prepare && size == 0 && ! i->t->system){
     110        3180 :                                                 setFunctionId(p, emptybindidxRef);
     111             :                                         }
     112             :                                 }
     113             :                         }
     114             :                 }
     115             :         }
     116      570127 :         return space;
     117             : }
     118             : 
     119             : /* gather the optimizer pipeline defined in the current session */
     120             : str
     121      823951 : getSQLoptimizer(mvc *m)
     122             : {
     123      823951 :         char *opt = get_string_global_var(m, "optimizer");
     124      826252 :         char *pipe = "default_pipe";
     125      826252 :         char *rec_pipe = "recursive_pipe";
     126             : 
     127      826252 :         if (m->recursive)
     128             :                 return rec_pipe;
     129             : 
     130      826125 :         if (opt)
     131      826125 :                 pipe = opt;
     132             :         return pipe;
     133             : }
     134             : 
     135             : static str
     136      570219 : addOptimizers(Client c, MalBlkPtr mb, char *pipe, int prepare)
     137             : {
     138      570219 :         int i;
     139      570219 :         InstrPtr q;
     140      570219 :         backend *be;
     141      570219 :         str msg= MAL_SUCCEED;
     142             : 
     143      570219 :         be = (backend *) c->sqlcontext;
     144      570219 :         assert(be && be->mvc);       /* SQL clients should always have their state set */
     145             : 
     146      570219 :         (void) SQLgetSpace(be->mvc, mb, prepare); // detect empty bats.
     147      569906 :         pipe = pipe? pipe: "default_pipe";
     148      569906 :         msg = addOptimizerPipe(c, mb, pipe);
     149      570312 :         if (msg){
     150             :                 return msg;
     151             :         }
     152      570313 :         if (be->no_mitosis) {
     153     4265967 :                 for (i = mb->stop - 1; i > 0; i--) {
     154     4265968 :                         q = getInstrPtr(mb, i);
     155     4265968 :                         if (q->token == ENDsymbol)
     156             :                                 break;
     157     4033050 :                         if (getFunctionId(q) == mitosisRef)
     158      128825 :                                 q->token = REMsymbol;        /* they are ignored */
     159             :                 }
     160             :         }
     161             :         return msg;
     162             : }
     163             : 
     164             : /* Queries that should rely on the latest consolidated state
     165             :  * are not allowed to remove sql.binds operations.
     166             :  */
     167             : 
     168             : str
     169         826 : SQLoptimizeFunction(Client c, MalBlkPtr mb)
     170             : {
     171         826 :         str msg;
     172         826 :         str pipe;
     173         826 :         backend *be = (backend *) c->sqlcontext;
     174         826 :         assert(be && be->mvc);       /* SQL clients should always have their state set */
     175             : 
     176         826 :         pipe = getSQLoptimizer(be->mvc);
     177         826 :         msg = addOptimizers(c, mb, pipe, TRUE);
     178         826 :         if (msg)
     179             :                 return msg;
     180         826 :         msg = optimizeMALBlock(c, mb);
     181         826 :         return msg;
     182             : }
     183             : 
     184             : str
     185      567942 : SQLoptimizeQuery(Client c, MalBlkPtr mb)
     186             : {
     187      567942 :         backend *be;
     188      567942 :         str msg = 0, pipe = 0;
     189      567942 :         bool free_pipe = false;
     190      567942 :         InstrPtr p = mb->stmt[mb->stop -1];
     191             : 
     192      567942 :         if (p && mb->stop > 0 && getModuleId(p) == optimizerRef)
     193             :                 return MAL_SUCCEED; /* already optimized */
     194             : 
     195      567942 :         be = (backend *) c->sqlcontext;
     196      567942 :         assert(be && be->mvc);       /* SQL clients should always have their state set */
     197             : 
     198      567942 :         c->blkmode = 0;
     199      567942 :         msg = chkProgram(c->usermodule, mb);
     200             : 
     201             :         /*
     202             :          * An error in the compilation should be reported to the user.
     203             :          * And if the debugging option is set, the debugger is called
     204             :          * to allow inspection.
     205             :          */
     206      568813 :         if (msg != MAL_SUCCEED || mb->errors) {
     207           1 :                 if (c->listing)
     208           0 :                         printFunction(c->fdout, mb, 0, c->listing);
     209           1 :                 if (mb->errors && msg && msg != mb->errors) { /* if both set, throw mb->errors as the earliest one */
     210           0 :                         freeException(msg);
     211           0 :                         msg = MAL_SUCCEED;
     212             :                 }
     213           1 :                 str nmsg = createException(MAL, "optimizer.optimizeQuery", "%s", mb->errors ? mb->errors : msg);
     214           1 :                 freeException(msg);
     215           1 :                 return nmsg;
     216             :         }
     217             : 
     218      568812 :         pipe = getSQLoptimizer(be->mvc);
     219      569378 :         if( strcmp(pipe, "default_pipe") == 0 && strcmp(c->optimizer, "default_pipe") != 0) {
     220          15 :                 if (!(pipe = GDKstrdup(c->optimizer)))
     221           0 :                         throw(MAL, "sql.optimizeQuery", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     222             :                 free_pipe = true;
     223             :         }
     224             : 
     225      569378 :         msg = addOptimizers(c, mb, pipe, FALSE);
     226      569483 :         if (free_pipe)
     227          15 :                 GDKfree(pipe);
     228      569483 :         if (msg)
     229             :                 return msg;
     230      569485 :         msg = optimizeMALBlock(c, mb);
     231      569485 :         return msg;
     232             : }
     233             : 
     234             : /* queries are added to the MAL catalog  under the client session namespace */
     235             : void
     236         701 : SQLaddQueryToCache(Client c)
     237             : {
     238         701 :         insertSymbol(c->usermodule, c->curprg);
     239         702 : }
     240             : 
     241             : void
     242           0 : SQLremoveQueryFromCache(Client c)
     243             : {
     244           0 :         deleteSymbol(c->usermodule, c->curprg);
     245           0 : }

Generated by: LCOV version 1.14