LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_optimizer.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 98 113 86.7 %
Date: 2024-10-04 20:04:04 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 "opt_prelude.h"
      21             : #include "sql_mvc.h"
      22             : #include "sql_optimizer.h"
      23             : #include "sql_scenario.h"
      24             : #include "sql_gencode.h"
      25             : #include "opt_pipes.h"
      26             : 
      27             : /* calculate the footprint for optimizer pipe line choices
      28             :  * and identify empty columns upfront for just in time optimizers.
      29             :  */
      30             : static lng
      31      980444 : SQLgetColumnSize(sql_trans *tr, sql_column *c, int access)
      32             : {
      33      980444 :         sqlstore *store = tr->store;
      34     1960891 :         return store->storage_api.count_col(tr, c, access);
      35             : }
      36             : 
      37             : static lng
      38        6467 : SQLgetIdxSize(sql_trans *tr, sql_idx *i, int access)
      39             : {
      40        6467 :         sqlstore *store = tr->store;
      41        6467 :         return store->storage_api.count_idx(tr, i, access);
      42             : }
      43             : 
      44             : 
      45             : /*
      46             :  * The maximal space occupied by a query is calculated
      47             :  * under the assumption that the complete database should fit in memory.
      48             :  * The assumption is that the plan does not contain duplicate bind operations.
      49             :  * Calculation of the precise footprint is much more complex
      50             :  * and can not deal with intermediate structures, or fast
      51             :  * access using sorted probing.
      52             :  *
      53             :  * A run where we only take the size of a table only once,
      54             :  * caused major degradation on SF100 Q3 with SSD(>6x)
      55             :  */
      56             : 
      57             : static lng
      58      566404 : SQLgetSpace(mvc *m, MalBlkPtr mb, int prepare)
      59             : {
      60      566404 :         sql_trans *tr = m->session->tr;
      61      566404 :         lng size,space = 0, i;
      62      566404 :         str lasttable = 0;
      63             : 
      64    14223133 :         for (i = 0; i < mb->stop; i++) {
      65    13656725 :                 InstrPtr p = mb->stmt[i];
      66             : 
      67             :                 /* now deal with the update binds, it is only necessary to identify that there are updates
      68             :                  * The actual size is not that important */
      69    13656725 :                 if (getModuleId(p) == sqlRef && getFunctionId(p) == bindRef  && p->retc <= 2){
      70      980443 :                         char *sname = getVarConstant(mb, getArg(p, 1 + p->retc)).val.sval;
      71      980443 :                         char *tname = getVarConstant(mb, getArg(p, 2 + p->retc)).val.sval;
      72      980443 :                         char *cname = getVarConstant(mb, getArg(p, 3 + p->retc)).val.sval;
      73      980443 :                         int access = getVarConstant(mb, getArg(p, 4 + p->retc)).val.ival;
      74      980443 :                         sql_schema *s = mvc_bind_schema(m, sname);
      75      980449 :                         sql_table *t = 0;
      76      980449 :                         sql_column *c = 0;
      77             : 
      78      980449 :                         if (!s)
      79           0 :                                 continue;
      80      980449 :                         t = mvc_bind_table(m, s, tname);
      81      980450 :                         if (!t || isDeclaredTable(t))
      82           0 :                                 continue;
      83      980450 :                         c = mvc_bind_column(m, t, cname);
      84      980444 :                         if (!c)
      85           0 :                                 continue;
      86             : 
      87             :                         /* we have to sum the cost of all three components of a BAT */
      88      980444 :                         if (c && isTable(c->t) && (lasttable == 0 || strcmp(lasttable,tname)==0)) {
      89      980444 :                                 size = SQLgetColumnSize(tr, c, access);
      90      980447 :                                 space += size;  // accumulate once per table
      91             :                                 //lasttable = tname;     invalidate this attempt
      92      980447 :                                 if( !prepare && size == 0  && ! t->system){
      93      285333 :                                         setFunctionId(p, emptybindRef);
      94             :                                 }
      95             :                         }
      96             :                 }
      97    13656729 :                 if (getModuleId(p) == sqlRef && (getFunctionId(p) == bindidxRef)) {
      98        6467 :                         char *sname = getVarConstant(mb, getArg(p, 1 + p->retc)).val.sval;
      99             :                         //char *tname = getVarConstant(mb, getArg(p, 2 + p->retc)).val.sval;
     100        6467 :                         char *idxname = getVarConstant(mb, getArg(p, 3 + p->retc)).val.sval;
     101        6467 :                         int access = getVarConstant(mb, getArg(p, 4 + p->retc)).val.ival;
     102        6467 :                         sql_schema *s = mvc_bind_schema(m, sname);
     103             : 
     104        6467 :                         if (getFunctionId(p) == bindidxRef) {
     105        6467 :                                 sql_idx *i = mvc_bind_idx(m, s, idxname);
     106             : 
     107        6467 :                                 if (i && isTable(i->t)) {
     108        6467 :                                         size = SQLgetIdxSize(tr, i, access);
     109             : 
     110        6467 :                                         if( !prepare && size == 0 && ! i->t->system){
     111        3180 :                                                 setFunctionId(p, emptybindidxRef);
     112             :                                         }
     113             :                                 }
     114             :                         }
     115             :                 }
     116             :         }
     117      566408 :         return space;
     118             : }
     119             : 
     120             : /* gather the optimizer pipeline defined in the current session */
     121             : str
     122      821524 : getSQLoptimizer(mvc *m)
     123             : {
     124      821524 :         char *opt = get_string_global_var(m, "optimizer");
     125      821484 :         char *pipe = "default_pipe";
     126             : 
     127      821484 :         if (opt)
     128      821484 :                 pipe = opt;
     129      821484 :         return pipe;
     130             : }
     131             : 
     132             : static str
     133      566403 : addOptimizers(Client c, MalBlkPtr mb, char *pipe, int prepare)
     134             : {
     135      566403 :         int i;
     136      566403 :         InstrPtr q;
     137      566403 :         backend *be;
     138      566403 :         str msg= MAL_SUCCEED;
     139             : 
     140      566403 :         be = (backend *) c->sqlcontext;
     141      566403 :         assert(be && be->mvc);       /* SQL clients should always have their state set */
     142             : 
     143      566403 :         (void) SQLgetSpace(be->mvc, mb, prepare); // detect empty bats.
     144      566398 :         pipe = pipe? pipe: "default_pipe";
     145      566398 :         msg = addOptimizerPipe(c, mb, pipe);
     146      566412 :         if (msg){
     147             :                 return msg;
     148             :         }
     149      566412 :         if (be->no_mitosis) {
     150     4248206 :                 for (i = mb->stop - 1; i > 0; i--) {
     151     4248206 :                         q = getInstrPtr(mb, i);
     152     4248206 :                         if (q->token == ENDsymbol)
     153             :                                 break;
     154     4015857 :                         if (getFunctionId(q) == mitosisRef)
     155      128249 :                                 q->token = REMsymbol;        /* they are ignored */
     156             :                 }
     157             :         }
     158             :         return msg;
     159             : }
     160             : 
     161             : /* Queries that should rely on the latest consolidated state
     162             :  * are not allowed to remove sql.binds operations.
     163             :  */
     164             : 
     165             : str
     166         822 : SQLoptimizeFunction(Client c, MalBlkPtr mb)
     167             : {
     168         822 :         str msg;
     169         822 :         str pipe;
     170         822 :         backend *be = (backend *) c->sqlcontext;
     171         822 :         assert(be && be->mvc);       /* SQL clients should always have their state set */
     172             : 
     173         822 :         pipe = getSQLoptimizer(be->mvc);
     174         822 :         msg = addOptimizers(c, mb, pipe, TRUE);
     175         822 :         if (msg)
     176             :                 return msg;
     177         822 :         msg = optimizeMALBlock(c, mb);
     178         822 :         return msg;
     179             : }
     180             : 
     181             : str
     182      565571 : SQLoptimizeQuery(Client c, MalBlkPtr mb)
     183             : {
     184      565571 :         backend *be;
     185      565571 :         str msg = 0, pipe = 0;
     186      565571 :         bool free_pipe = false;
     187      565571 :         InstrPtr p = mb->stmt[mb->stop -1];
     188             : 
     189      565571 :         if (p && mb->stop > 0 && getModuleId(p) == optimizerRef)
     190             :                 return MAL_SUCCEED; /* already optimized */
     191             : 
     192      565571 :         be = (backend *) c->sqlcontext;
     193      565571 :         assert(be && be->mvc);       /* SQL clients should always have their state set */
     194             : 
     195      565571 :         c->blkmode = 0;
     196      565571 :         msg = chkProgram(c->usermodule, mb);
     197             : 
     198             :         /*
     199             :          * An error in the compilation should be reported to the user.
     200             :          * And if the debugging option is set, the debugger is called
     201             :          * to allow inspection.
     202             :          */
     203      565585 :         if (msg != MAL_SUCCEED || mb->errors) {
     204           0 :                 if (c->listing)
     205           0 :                         printFunction(c->fdout, mb, 0, c->listing);
     206           0 :                 if (mb->errors && msg && msg != mb->errors) { /* if both set, throw mb->errors as the earliest one */
     207           0 :                         freeException(msg);
     208           0 :                         msg = MAL_SUCCEED;
     209             :                 }
     210           0 :                 str nmsg = createException(MAL, "optimizer.optimizeQuery", "%s", mb->errors ? mb->errors : msg);
     211           0 :                 freeException(msg);
     212           0 :                 return nmsg;
     213             :         }
     214             : 
     215      565585 :         pipe = getSQLoptimizer(be->mvc);
     216      565585 :         if( strcmp(pipe, "default_pipe") == 0 && strcmp(c->optimizer, "default_pipe") != 0) {
     217          15 :                 if (!(pipe = GDKstrdup(c->optimizer)))
     218           0 :                         throw(MAL, "sql.optimizeQuery", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     219             :                 free_pipe = true;
     220             :         }
     221             : 
     222      565585 :         msg = addOptimizers(c, mb, pipe, FALSE);
     223      565590 :         if (free_pipe)
     224          15 :                 GDKfree(pipe);
     225      565590 :         if (msg)
     226             :                 return msg;
     227      565590 :         msg = optimizeMALBlock(c, mb);
     228      565590 :         return msg;
     229             : }
     230             : 
     231             : /* queries are added to the MAL catalog  under the client session namespace */
     232             : void
     233         702 : SQLaddQueryToCache(Client c)
     234             : {
     235         702 :         insertSymbol(c->usermodule, c->curprg);
     236         702 : }
     237             : 
     238             : void
     239           0 : SQLremoveQueryFromCache(Client c)
     240             : {
     241           0 :         deleteSymbol(c->usermodule, c->curprg);
     242           0 : }

Generated by: LCOV version 1.14