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-19 23:10:26 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      996238 : SQLgetColumnSize(sql_trans *tr, sql_column *c, int access)
      31             : {
      32      996238 :         sqlstore *store = tr->store;
      33     1992459 :         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      569219 : SQLgetSpace(mvc *m, MalBlkPtr mb, int prepare)
      58             : {
      59      569219 :         sql_trans *tr = m->session->tr;
      60      569219 :         lng size,space = 0, i;
      61      569219 :         str lasttable = 0;
      62             : 
      63    14334579 :         for (i = 0; i < mb->stop; i++) {
      64    13765392 :                 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    13765392 :                 if (getModuleId(p) == sqlRef && getFunctionId(p) == bindRef  && p->retc <= 2){
      69      996247 :                         char *sname = getVarConstant(mb, getArg(p, 1 + p->retc)).val.sval;
      70      996247 :                         char *tname = getVarConstant(mb, getArg(p, 2 + p->retc)).val.sval;
      71      996247 :                         char *cname = getVarConstant(mb, getArg(p, 3 + p->retc)).val.sval;
      72      996247 :                         int access = getVarConstant(mb, getArg(p, 4 + p->retc)).val.ival;
      73      996247 :                         sql_schema *s = mvc_bind_schema(m, sname);
      74      996249 :                         sql_table *t = 0;
      75      996249 :                         sql_column *c = 0;
      76             : 
      77      996249 :                         if (!s)
      78           0 :                                 continue;
      79      996249 :                         t = mvc_bind_table(m, s, tname);
      80      996254 :                         if (!t || isDeclaredTable(t))
      81           0 :                                 continue;
      82      996254 :                         c = mvc_bind_column(m, t, cname);
      83      996231 :                         if (!c)
      84           0 :                                 continue;
      85             : 
      86             :                         /* we have to sum the cost of all three components of a BAT */
      87      996231 :                         if (c && isTable(c->t) && (lasttable == 0 || strcmp(lasttable,tname)==0)) {
      88      996238 :                                 size = SQLgetColumnSize(tr, c, access);
      89      996221 :                                 space += size;  // accumulate once per table
      90             :                                 //lasttable = tname;     invalidate this attempt
      91      996221 :                                 if( !prepare && size == 0  && ! t->system){
      92      284658 :                                         setFunctionId(p, emptybindRef);
      93             :                                 }
      94             :                         }
      95             :                 }
      96    13765360 :                 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      569187 :         return space;
     117             : }
     118             : 
     119             : /* gather the optimizer pipeline defined in the current session */
     120             : str
     121      823420 : getSQLoptimizer(mvc *m)
     122             : {
     123      823420 :         char *opt = get_string_global_var(m, "optimizer");
     124      825333 :         char *pipe = "default_pipe";
     125      825333 :         char *rec_pipe = "recursive_pipe";
     126             : 
     127      825333 :         if (m->recursive)
     128             :                 return rec_pipe;
     129             : 
     130      825208 :         if (opt)
     131      825208 :                 pipe = opt;
     132             :         return pipe;
     133             : }
     134             : 
     135             : static str
     136      569223 : addOptimizers(Client c, MalBlkPtr mb, char *pipe, int prepare)
     137             : {
     138      569223 :         int i;
     139      569223 :         InstrPtr q;
     140      569223 :         backend *be;
     141      569223 :         str msg= MAL_SUCCEED;
     142             : 
     143      569223 :         be = (backend *) c->sqlcontext;
     144      569223 :         assert(be && be->mvc);       /* SQL clients should always have their state set */
     145             : 
     146      569223 :         (void) SQLgetSpace(be->mvc, mb, prepare); // detect empty bats.
     147      568997 :         pipe = pipe? pipe: "default_pipe";
     148      568997 :         msg = addOptimizerPipe(c, mb, pipe);
     149      569369 :         if (msg){
     150             :                 return msg;
     151             :         }
     152      569369 :         if (be->no_mitosis) {
     153     4265346 :                 for (i = mb->stop - 1; i > 0; i--) {
     154     4265346 :                         q = getInstrPtr(mb, i);
     155     4265346 :                         if (q->token == ENDsymbol)
     156             :                                 break;
     157     4032406 :                         if (getFunctionId(q) == mitosisRef)
     158      128804 :                                 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         822 : SQLoptimizeFunction(Client c, MalBlkPtr mb)
     170             : {
     171         822 :         str msg;
     172         822 :         str pipe;
     173         822 :         backend *be = (backend *) c->sqlcontext;
     174         822 :         assert(be && be->mvc);       /* SQL clients should always have their state set */
     175             : 
     176         822 :         pipe = getSQLoptimizer(be->mvc);
     177         822 :         msg = addOptimizers(c, mb, pipe, TRUE);
     178         822 :         if (msg)
     179             :                 return msg;
     180         822 :         msg = optimizeMALBlock(c, mb);
     181         822 :         return msg;
     182             : }
     183             : 
     184             : str
     185      567171 : SQLoptimizeQuery(Client c, MalBlkPtr mb)
     186             : {
     187      567171 :         backend *be;
     188      567171 :         str msg = 0, pipe = 0;
     189      567171 :         bool free_pipe = false;
     190      567171 :         InstrPtr p = mb->stmt[mb->stop -1];
     191             : 
     192      567171 :         if (p && mb->stop > 0 && getModuleId(p) == optimizerRef)
     193             :                 return MAL_SUCCEED; /* already optimized */
     194             : 
     195      567171 :         be = (backend *) c->sqlcontext;
     196      567171 :         assert(be && be->mvc);       /* SQL clients should always have their state set */
     197             : 
     198      567171 :         c->blkmode = 0;
     199      567171 :         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      567804 :         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      567803 :         pipe = getSQLoptimizer(be->mvc);
     219      568473 :         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      568473 :         msg = addOptimizers(c, mb, pipe, FALSE);
     226      568544 :         if (free_pipe)
     227          15 :                 GDKfree(pipe);
     228      568544 :         if (msg)
     229             :                 return msg;
     230      568544 :         msg = optimizeMALBlock(c, mb);
     231      568544 :         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         701 : }
     240             : 
     241             : void
     242           0 : SQLremoveQueryFromCache(Client c)
     243             : {
     244           0 :         deleteSymbol(c->usermodule, c->curprg);
     245           0 : }

Generated by: LCOV version 1.14