~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/optimizer/explain_plan.cc

  • Committer: Brian Aker
  • Date: 2010-02-07 01:33:54 UTC
  • Revision ID: brian@gaz-20100207013354-d2pg1n68u5c09pgo
Remove giant include header to its own file.

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