~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/optimizer/explain_plan.cc

Merged vcol stuff.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2008-2009 Sun Microsystems, Inc.
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; version 2 of the License.
9
 
 *
10
 
 *  This program is distributed in the hope that it will be useful,
11
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
 *  GNU General Public License for more details.
14
 
 *
15
 
 *  You should have received a copy of the GNU General Public License
16
 
 *  along with this program; if not, write to the Free Software
17
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
 */
19
 
 
20
 
#include "config.h"
21
 
#include "drizzled/session.h"
22
 
#include "drizzled/item/uint.h"
23
 
#include "drizzled/item/float.h"
24
 
#include "drizzled/item/string.h"
25
 
#include "drizzled/optimizer/explain_plan.h"
26
 
#include "drizzled/optimizer/position.h"
27
 
#include "drizzled/optimizer/quick_ror_intersect_select.h"
28
 
#include "drizzled/optimizer/range.h"
29
 
#include "drizzled/sql_select.h"
30
 
#include "drizzled/join.h"
31
 
#include "drizzled/internal/m_string.h"
32
 
 
33
 
#include <cstdio>
34
 
#include <string>
35
 
#include <sstream>
36
 
#include <bitset>
37
 
 
38
 
using namespace std;
39
 
 
40
 
namespace drizzled
41
 
{
42
 
 
43
 
static const string access_method_str[]=
44
 
{
45
 
  "UNKNOWN",
46
 
  "system",
47
 
  "const",
48
 
  "eq_ref",
49
 
  "ref",
50
 
  "MAYBE_REF",
51
 
  "ALL",
52
 
  "range",
53
 
  "index",
54
 
  "ref_or_null",
55
 
  "unique_subquery",
56
 
  "index_subquery",
57
 
  "index_merge"
58
 
};
59
 
 
60
 
static const string select_type_str[]=
61
 
{
62
 
  "PRIMARY",
63
 
  "SIMPLE",
64
 
  "DERIVED",
65
 
  "DEPENDENT SUBQUERY",
66
 
  "UNCACHEABLE SUBQUERY",
67
 
  "SUBQUERY",
68
 
  "DEPENDENT UNION",
69
 
  "UNCACHEABLE_UNION",
70
 
  "UNION",
71
 
  "UNION RESULT"
72
 
};
73
 
 
74
 
void optimizer::ExplainPlan::printPlan()
75
 
{
76
 
  List<Item> field_list;
77
 
  List<Item> item_list;
78
 
  Session *session= join->session;
79
 
  select_result *result= join->result;
80
 
  Item *item_null= new Item_null();
81
 
  const CHARSET_INFO * const cs= system_charset_info;
82
 
  int quick_type;
83
 
  /* Don't log this into the slow query log */
84
 
  session->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
85
 
  join->unit->offset_limit_cnt= 0;
86
 
 
87
 
  /*
88
 
   NOTE: the number/types of items pushed into item_list must be in sync with
89
 
   EXPLAIN column types as they're "defined" in Session::send_explain_fields()
90
 
   */
91
 
  if (message)
92
 
  {
93
 
    item_list.push_back(new Item_int((int32_t)
94
 
                        join->select_lex->select_number));
95
 
    item_list.push_back(new Item_string(select_type_str[join->select_lex->type].c_str(),
96
 
                                        select_type_str[join->select_lex->type].length(),
97
 
                                        cs));
98
 
    for (uint32_t i= 0; i < 7; i++)
99
 
      item_list.push_back(item_null);
100
 
 
101
 
    if (join->session->lex->describe & DESCRIBE_EXTENDED)
102
 
      item_list.push_back(item_null);
103
 
 
104
 
    item_list.push_back(new Item_string(message,strlen(message),cs));
105
 
    if (result->send_data(item_list))
106
 
      join->error= 1;
107
 
  }
108
 
  else if (join->select_lex == join->unit->fake_select_lex)
109
 
  {
110
 
    /*
111
 
       here we assume that the query will return at least two rows, so we
112
 
       show "filesort" in EXPLAIN. Of course, sometimes we'll be wrong
113
 
       and no filesort will be actually done, but executing all selects in
114
 
       the UNION to provide precise EXPLAIN information will hardly be
115
 
       appreciated :)
116
 
     */
117
 
    char table_name_buffer[NAME_LEN];
118
 
    item_list.empty();
119
 
    /* id */
120
 
    item_list.push_back(new Item_null);
121
 
    /* select_type */
122
 
    item_list.push_back(new Item_string(select_type_str[join->select_lex->type].c_str(),
123
 
                                        select_type_str[join->select_lex->type].length(),
124
 
                                        cs));
125
 
    /* table */
126
 
    {
127
 
      Select_Lex *sl= join->unit->first_select();
128
 
      uint32_t len= 6, lastop= 0;
129
 
      memcpy(table_name_buffer, STRING_WITH_LEN("<union"));
130
 
      for (; sl && len + lastop + 5 < NAME_LEN; sl= sl->next_select())
131
 
      {
132
 
        len+= lastop;
133
 
        lastop= snprintf(table_name_buffer + len, NAME_LEN - len,
134
 
            "%u,", sl->select_number);
135
 
      }
136
 
      if (sl || len + lastop >= NAME_LEN)
137
 
      {
138
 
        memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1);
139
 
        len+= 4;
140
 
      }
141
 
      else
142
 
      {
143
 
        len+= lastop;
144
 
        table_name_buffer[len - 1]= '>';  // change ',' to '>'
145
 
      }
146
 
      item_list.push_back(new Item_string(table_name_buffer, len, cs));
147
 
    }
148
 
    /* type */
149
 
    item_list.push_back(new Item_string(access_method_str[AM_ALL].c_str(),
150
 
                                        access_method_str[AM_ALL].length(),
151
 
                                        cs));
152
 
    /* possible_keys */
153
 
    item_list.push_back(item_null);
154
 
    /* key*/
155
 
    item_list.push_back(item_null);
156
 
    /* key_len */
157
 
    item_list.push_back(item_null);
158
 
    /* ref */
159
 
    item_list.push_back(item_null);
160
 
    /* in_rows */
161
 
    if (join->session->lex->describe & DESCRIBE_EXTENDED)
162
 
      item_list.push_back(item_null);
163
 
    /* rows */
164
 
    item_list.push_back(item_null);
165
 
    /* extra */
166
 
    if (join->unit->global_parameters->order_list.first)
167
 
      item_list.push_back(new Item_string("Using filesort",
168
 
                                          14, 
169
 
                                          cs));
170
 
    else
171
 
      item_list.push_back(new Item_string("", 0, cs));
172
 
 
173
 
    if (result->send_data(item_list))
174
 
      join->error= 1;
175
 
  }
176
 
  else
177
 
  {
178
 
    table_map used_tables= 0;
179
 
    for (uint32_t i= 0; i < join->tables; i++)
180
 
    {
181
 
      JoinTable *tab= join->join_tab + i;
182
 
      Table *table= tab->table;
183
 
      char buff[512];
184
 
      char buff1[512], buff2[512], buff3[512];
185
 
      char keylen_str_buf[64];
186
 
      String extra(buff, sizeof(buff),cs);
187
 
      char table_name_buffer[NAME_LEN];
188
 
      String tmp1(buff1,sizeof(buff1),cs);
189
 
      String tmp2(buff2,sizeof(buff2),cs);
190
 
      String tmp3(buff3,sizeof(buff3),cs);
191
 
      extra.length(0);
192
 
      tmp1.length(0);
193
 
      tmp2.length(0);
194
 
      tmp3.length(0);
195
 
 
196
 
      quick_type= -1;
197
 
      item_list.empty();
198
 
      /* id */
199
 
      item_list.push_back(new Item_uint((uint32_t)
200
 
            join->select_lex->select_number));
201
 
      /* select_type */
202
 
      item_list.push_back(new Item_string(select_type_str[join->select_lex->type].c_str(),
203
 
                                          select_type_str[join->select_lex->type].length(),
204
 
                                          cs));
205
 
      if (tab->type == AM_ALL && tab->select && tab->select->quick)
206
 
      {
207
 
        quick_type= tab->select->quick->get_type();
208
 
        if ((quick_type == optimizer::QuickSelectInterface::QS_TYPE_INDEX_MERGE) ||
209
 
            (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT) ||
210
 
            (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_UNION))
211
 
          tab->type = AM_INDEX_MERGE;
212
 
        else
213
 
          tab->type = AM_RANGE;
214
 
      }
215
 
      /* table */
216
 
      if (table->derived_select_number)
217
 
      {
218
 
        /* Derived table name generation */
219
 
        int len= snprintf(table_name_buffer, 
220
 
                          sizeof(table_name_buffer)-1,
221
 
                          "<derived%u>",
222
 
                          table->derived_select_number);
223
 
        item_list.push_back(new Item_string(table_name_buffer, len, cs));
224
 
      }
225
 
      else
226
 
      {
227
 
        TableList *real_table= table->pos_in_table_list;
228
 
        item_list.push_back(new Item_string(real_table->alias,
229
 
                                            strlen(real_table->alias),
230
 
                                            cs));
231
 
      }
232
 
      /* "type" column */
233
 
      item_list.push_back(new Item_string(access_method_str[tab->type].c_str(),
234
 
                                          access_method_str[tab->type].length(),
235
 
                                          cs));
236
 
      /* Build "possible_keys" value and add it to item_list */
237
 
      if (tab->keys.any())
238
 
      {
239
 
        for (uint32_t j= 0; j < table->getShare()->sizeKeys(); j++)
240
 
        {
241
 
          if (tab->keys.test(j))
242
 
          {
243
 
            if (tmp1.length())
244
 
              tmp1.append(',');
245
 
            tmp1.append(table->key_info[j].name,
246
 
                        strlen(table->key_info[j].name),
247
 
                        system_charset_info);
248
 
          }
249
 
        }
250
 
      }
251
 
      if (tmp1.length())
252
 
        item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
253
 
      else
254
 
        item_list.push_back(item_null);
255
 
 
256
 
      /* Build "key", "key_len", and "ref" values and add them to item_list */
257
 
      if (tab->ref.key_parts)
258
 
      {
259
 
        KeyInfo *key_info= table->key_info+ tab->ref.key;
260
 
        item_list.push_back(new Item_string(key_info->name,
261
 
                                            strlen(key_info->name),
262
 
                                            system_charset_info));
263
 
        uint32_t length= internal::int64_t2str(tab->ref.key_length, keylen_str_buf, 10) -
264
 
                                     keylen_str_buf;
265
 
        item_list.push_back(new Item_string(keylen_str_buf, 
266
 
                                            length,
267
 
                                            system_charset_info));
268
 
        for (StoredKey **ref= tab->ref.key_copy; *ref; ref++)
269
 
        {
270
 
          if (tmp2.length())
271
 
            tmp2.append(',');
272
 
          tmp2.append((*ref)->name(), 
273
 
                       strlen((*ref)->name()),
274
 
                       system_charset_info);
275
 
        }
276
 
        item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
277
 
      }
278
 
      else if (tab->type == AM_NEXT)
279
 
      {
280
 
        KeyInfo *key_info=table->key_info+ tab->index;
281
 
        item_list.push_back(new Item_string(key_info->name,
282
 
              strlen(key_info->name),cs));
283
 
        uint32_t length= internal::int64_t2str(key_info->key_length, keylen_str_buf, 10) -
284
 
                                     keylen_str_buf;
285
 
        item_list.push_back(new Item_string(keylen_str_buf,
286
 
                                            length,
287
 
                                            system_charset_info));
288
 
        item_list.push_back(item_null);
289
 
      }
290
 
      else if (tab->select && tab->select->quick)
291
 
      {
292
 
        tab->select->quick->add_keys_and_lengths(&tmp2, &tmp3);
293
 
        item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
294
 
        item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
295
 
        item_list.push_back(item_null);
296
 
      }
297
 
      else
298
 
      {
299
 
        item_list.push_back(item_null);
300
 
        item_list.push_back(item_null);
301
 
        item_list.push_back(item_null);
302
 
      }
303
 
 
304
 
      /* Add "rows" field to item_list. */
305
 
      double examined_rows;
306
 
      if (tab->select && tab->select->quick)
307
 
      {
308
 
        examined_rows= rows2double(tab->select->quick->records);
309
 
      }
310
 
      else if (tab->type == AM_NEXT || tab->type == AM_ALL)
311
 
      {
312
 
        examined_rows= rows2double(tab->limit ? tab->limit :
313
 
                                                tab->table->cursor->records());
314
 
      }
315
 
      else
316
 
      {
317
 
        optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
318
 
        examined_rows= cur_pos.getFanout();
319
 
      }
320
 
 
321
 
      item_list.push_back(new Item_int((int64_t) (uint64_t) examined_rows,
322
 
                                       MY_INT64_NUM_DECIMAL_DIGITS));
323
 
 
324
 
      /* Add "filtered" field to item_list. */
325
 
      if (join->session->lex->describe & DESCRIBE_EXTENDED)
326
 
      {
327
 
        float f= 0.0;
328
 
        if (examined_rows)
329
 
        {
330
 
          optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
331
 
          f= static_cast<float>(100.0 * cur_pos.getFanout() / examined_rows);
332
 
        }
333
 
        item_list.push_back(new Item_float(f, 2));
334
 
      }
335
 
 
336
 
      /* Build "Extra" field and add it to item_list. */
337
 
      bool key_read= table->key_read;
338
 
      if ((tab->type == AM_NEXT || tab->type == AM_CONST) &&
339
 
          table->covering_keys.test(tab->index))
340
 
        key_read= 1;
341
 
      if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT &&
342
 
          ! ((optimizer::QuickRorIntersectSelect *) tab->select->quick)->need_to_fetch_row)
343
 
        key_read= 1;
344
 
 
345
 
      if (tab->info)
346
 
        item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
347
 
      else if (tab->packed_info & TAB_INFO_HAVE_VALUE)
348
 
      {
349
 
        if (tab->packed_info & TAB_INFO_USING_INDEX)
350
 
          extra.append(STRING_WITH_LEN("; Using index"));
351
 
        if (tab->packed_info & TAB_INFO_USING_WHERE)
352
 
          extra.append(STRING_WITH_LEN("; Using where"));
353
 
        if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL)
354
 
          extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
355
 
        /* Skip initial "; "*/
356
 
        const char *str= extra.ptr();
357
 
        uint32_t len= extra.length();
358
 
        if (len)
359
 
        {
360
 
          str += 2;
361
 
          len -= 2;
362
 
        }
363
 
        item_list.push_back(new Item_string(str, len, cs));
364
 
      }
365
 
      else
366
 
      {
367
 
        uint32_t keyno= MAX_KEY;
368
 
        if (tab->ref.key_parts)
369
 
          keyno= tab->ref.key;
370
 
        else if (tab->select && tab->select->quick)
371
 
          keyno = tab->select->quick->index;
372
 
 
373
 
        if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_UNION ||
374
 
            quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT ||
375
 
            quick_type == optimizer::QuickSelectInterface::QS_TYPE_INDEX_MERGE)
376
 
        {
377
 
          extra.append(STRING_WITH_LEN("; Using "));
378
 
          tab->select->quick->add_info_string(&extra);
379
 
        }
380
 
        if (tab->select)
381
 
        {
382
 
          if (tab->use_quick == 2)
383
 
          {
384
 
            /*
385
 
             * To print out the bitset in tab->keys, we go through
386
 
             * it 32 bits at a time. We need to do this to ensure
387
 
             * that the to_ulong() method will not throw an
388
 
             * out_of_range exception at runtime which would happen
389
 
             * if the bitset we were working with was larger than 64
390
 
             * bits on a 64-bit platform (for example).
391
 
             */
392
 
            stringstream s, w;
393
 
            string str;
394
 
            w << tab->keys;
395
 
            w >> str;
396
 
            for (uint32_t pos= 0; pos < tab->keys.size(); pos+= 32)
397
 
            {
398
 
              bitset<32> tmp(str, pos, 32);
399
 
              if (tmp.any())
400
 
                s << uppercase << hex << tmp.to_ulong();
401
 
            }
402
 
            extra.append(STRING_WITH_LEN("; Range checked for each "
403
 
                  "record (index map: 0x"));
404
 
            extra.append(s.str().c_str());
405
 
            extra.append(')');
406
 
          }
407
 
          else if (tab->select->cond)
408
 
          {
409
 
            extra.append(STRING_WITH_LEN("; Using where"));
410
 
          }
411
 
        }
412
 
        if (key_read)
413
 
        {
414
 
          if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_GROUP_MIN_MAX)
415
 
            extra.append(STRING_WITH_LEN("; Using index for group-by"));
416
 
          else
417
 
            extra.append(STRING_WITH_LEN("; Using index"));
418
 
        }
419
 
        if (table->reginfo.not_exists_optimize)
420
 
          extra.append(STRING_WITH_LEN("; Not exists"));
421
 
 
422
 
        if (need_tmp_table)
423
 
        {
424
 
          need_tmp_table=0;
425
 
          extra.append(STRING_WITH_LEN("; Using temporary"));
426
 
        }
427
 
        if (need_order)
428
 
        {
429
 
          need_order=0;
430
 
          extra.append(STRING_WITH_LEN("; Using filesort"));
431
 
        }
432
 
        if (distinct & test_all_bits(used_tables,session->used_tables))
433
 
          extra.append(STRING_WITH_LEN("; Distinct"));
434
 
 
435
 
        if (tab->insideout_match_tab)
436
 
        {
437
 
          extra.append(STRING_WITH_LEN("; LooseScan"));
438
 
        }
439
 
 
440
 
        for (uint32_t part= 0; part < tab->ref.key_parts; part++)
441
 
        {
442
 
          if (tab->ref.cond_guards[part])
443
 
          {
444
 
            extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
445
 
            break;
446
 
          }
447
 
        }
448
 
 
449
 
        if (i > 0 && tab[-1].next_select == sub_select_cache)
450
 
          extra.append(STRING_WITH_LEN("; Using join buffer"));
451
 
 
452
 
        /* Skip initial "; "*/
453
 
        const char *str= extra.ptr();
454
 
        uint32_t len= extra.length();
455
 
        if (len)
456
 
        {
457
 
          str += 2;
458
 
          len -= 2;
459
 
        }
460
 
        item_list.push_back(new Item_string(str, len, cs));
461
 
      }
462
 
      // For next iteration
463
 
      used_tables|=table->map;
464
 
      if (result->send_data(item_list))
465
 
        join->error= 1;
466
 
    }
467
 
  }
468
 
  for (Select_Lex_Unit *unit= join->select_lex->first_inner_unit();
469
 
      unit;
470
 
      unit= unit->next_unit())
471
 
  {
472
 
    if (explainUnion(session, unit, result))
473
 
      return;
474
 
  }
475
 
  return;
476
 
}
477
 
 
478
 
bool optimizer::ExplainPlan::explainUnion(Session *session,
479
 
                                          Select_Lex_Unit *unit,
480
 
                                          select_result *result)
481
 
{
482
 
  bool res= false;
483
 
  Select_Lex *first= unit->first_select();
484
 
 
485
 
  for (Select_Lex *sl= first;
486
 
       sl;
487
 
       sl= sl->next_select())
488
 
  {
489
 
    // drop UNCACHEABLE_EXPLAIN, because it is for internal usage only
490
 
    sl->uncacheable.reset(UNCACHEABLE_EXPLAIN);
491
 
    if (&session->lex->select_lex == sl)
492
 
    {
493
 
      if (sl->first_inner_unit() || sl->next_select())
494
 
      {
495
 
        sl->type= optimizer::ST_PRIMARY;
496
 
      }
497
 
      else
498
 
      {
499
 
        sl->type= optimizer::ST_SIMPLE;
500
 
      }
501
 
    }
502
 
    else
503
 
    {
504
 
      if (sl == first)
505
 
      {
506
 
        if (sl->linkage == DERIVED_TABLE_TYPE)
507
 
        {
508
 
          sl->type= optimizer::ST_DERIVED;
509
 
        }
510
 
        else
511
 
        {
512
 
          if (sl->uncacheable.test(UNCACHEABLE_DEPENDENT))
513
 
          {
514
 
            sl->type= optimizer::ST_DEPENDENT_SUBQUERY;
515
 
          }
516
 
          else
517
 
          {
518
 
            if (sl->uncacheable.any())
519
 
            {
520
 
              sl->type= optimizer::ST_UNCACHEABLE_SUBQUERY;
521
 
            }
522
 
            else
523
 
            {
524
 
              sl->type= optimizer::ST_SUBQUERY;
525
 
            }
526
 
          }
527
 
        }
528
 
      }
529
 
      else
530
 
      {
531
 
        if (sl->uncacheable.test(UNCACHEABLE_DEPENDENT))
532
 
        {
533
 
          sl->type= optimizer::ST_DEPENDENT_UNION;
534
 
        }
535
 
        else
536
 
        {
537
 
          if (sl->uncacheable.any())
538
 
          {
539
 
            sl->type= optimizer::ST_UNCACHEABLE_UNION;
540
 
          }
541
 
          else
542
 
          {
543
 
            sl->type= optimizer::ST_UNION;
544
 
          }
545
 
        }
546
 
      }
547
 
    }
548
 
    sl->options|= SELECT_DESCRIBE;
549
 
  }
550
 
 
551
 
  if (unit->is_union())
552
 
  {
553
 
    unit->fake_select_lex->select_number= UINT_MAX; // just for initialization
554
 
    unit->fake_select_lex->type= optimizer::ST_UNION_RESULT;
555
 
    unit->fake_select_lex->options|= SELECT_DESCRIBE;
556
 
    if (! (res= unit->prepare(session, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
557
 
    {
558
 
      res= unit->exec();
559
 
    }
560
 
    res|= unit->cleanup();
561
 
  }
562
 
  else
563
 
  {
564
 
    session->lex->current_select= first;
565
 
    unit->set_limit(unit->global_parameters);
566
 
    res= select_query(session, 
567
 
                      &first->ref_pointer_array,
568
 
                      (TableList*) first->table_list.first,
569
 
                      first->with_wild, 
570
 
                      first->item_list,
571
 
                      first->where,
572
 
                      first->order_list.elements + first->group_list.elements,
573
 
                      (Order*) first->order_list.first,
574
 
                      (Order*) first->group_list.first,
575
 
                      first->having,
576
 
                      first->options | session->options | SELECT_DESCRIBE,
577
 
                      result, 
578
 
                      unit, 
579
 
                      first);
580
 
  }
581
 
  return (res || session->is_error());
582
 
}
583
 
 
584
 
} /* namespace drizzled */