1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008-2009 Sun Microsystems
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.
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.
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
20
#include "drizzled/server_includes.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"
34
using namespace drizzled;
36
static const string access_method_str[]=
53
void optimizer::ExplainPlan::printPlan()
55
List<Item> field_list;
57
Session *session= join->session;
58
select_result *result= join->result;
59
Item *item_null= new Item_null();
60
const CHARSET_INFO * const cs= system_charset_info;
62
/* Don't log this into the slow query log */
63
session->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
64
join->unit->offset_limit_cnt= 0;
67
NOTE: the number/types of items pushed into item_list must be in sync with
68
EXPLAIN column types as they're "defined" in Session::send_explain_fields()
72
item_list.push_back(new Item_int((int32_t)
73
join->select_lex->select_number));
74
item_list.push_back(new Item_string(join->select_lex->type.c_str(),
75
join->select_lex->type.length(),
77
for (uint32_t i= 0; i < 7; i++)
78
item_list.push_back(item_null);
80
if (join->session->lex->describe & DESCRIBE_EXTENDED)
81
item_list.push_back(item_null);
83
item_list.push_back(new Item_string(message,strlen(message),cs));
84
if (result->send_data(item_list))
87
else if (join->select_lex == join->unit->fake_select_lex)
90
here we assume that the query will return at least two rows, so we
91
show "filesort" in EXPLAIN. Of course, sometimes we'll be wrong
92
and no filesort will be actually done, but executing all selects in
93
the UNION to provide precise EXPLAIN information will hardly be
96
char table_name_buffer[NAME_LEN];
99
item_list.push_back(new Item_null);
101
item_list.push_back(new Item_string(join->select_lex->type.c_str(),
102
join->select_lex->type.length(),
106
Select_Lex *sl= join->unit->first_select();
107
uint32_t len= 6, lastop= 0;
108
memcpy(table_name_buffer, STRING_WITH_LEN("<union"));
109
for (; sl && len + lastop + 5 < NAME_LEN; sl= sl->next_select())
112
lastop= snprintf(table_name_buffer + len, NAME_LEN - len,
113
"%u,", sl->select_number);
115
if (sl || len + lastop >= NAME_LEN)
117
memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1);
123
table_name_buffer[len - 1]= '>'; // change ',' to '>'
125
item_list.push_back(new Item_string(table_name_buffer, len, cs));
128
item_list.push_back(new Item_string(access_method_str[AM_ALL].c_str(),
129
access_method_str[AM_ALL].length(),
132
item_list.push_back(item_null);
134
item_list.push_back(item_null);
136
item_list.push_back(item_null);
138
item_list.push_back(item_null);
140
if (join->session->lex->describe & DESCRIBE_EXTENDED)
141
item_list.push_back(item_null);
143
item_list.push_back(item_null);
145
if (join->unit->global_parameters->order_list.first)
146
item_list.push_back(new Item_string("Using filesort",
150
item_list.push_back(new Item_string("", 0, cs));
152
if (result->send_data(item_list))
157
table_map used_tables= 0;
158
for (uint32_t i= 0; i < join->tables; i++)
160
JoinTable *tab= join->join_tab + i;
161
Table *table= tab->table;
163
char buff1[512], buff2[512], buff3[512];
164
char keylen_str_buf[64];
165
String extra(buff, sizeof(buff),cs);
166
char table_name_buffer[NAME_LEN];
167
String tmp1(buff1,sizeof(buff1),cs);
168
String tmp2(buff2,sizeof(buff2),cs);
169
String tmp3(buff3,sizeof(buff3),cs);
178
item_list.push_back(new Item_uint((uint32_t)
179
join->select_lex->select_number));
181
item_list.push_back(new Item_string(join->select_lex->type.c_str(),
182
join->select_lex->type.length(),
184
if (tab->type == AM_ALL && tab->select && tab->select->quick)
186
quick_type= tab->select->quick->get_type();
187
if ((quick_type == optimizer::QuickSelectInterface::QS_TYPE_INDEX_MERGE) ||
188
(quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT) ||
189
(quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_UNION))
190
tab->type = AM_INDEX_MERGE;
192
tab->type = AM_RANGE;
195
if (table->derived_select_number)
197
/* Derived table name generation */
198
int len= snprintf(table_name_buffer,
199
sizeof(table_name_buffer)-1,
201
table->derived_select_number);
202
item_list.push_back(new Item_string(table_name_buffer, len, cs));
206
TableList *real_table= table->pos_in_table_list;
207
item_list.push_back(new Item_string(real_table->alias,
208
strlen(real_table->alias),
212
item_list.push_back(new Item_string(access_method_str[tab->type].c_str(),
213
access_method_str[tab->type].length(),
215
/* Build "possible_keys" value and add it to item_list */
218
for (uint32_t j= 0; j < table->s->keys; j++)
220
if (tab->keys.test(j))
224
tmp1.append(table->key_info[j].name,
225
strlen(table->key_info[j].name),
226
system_charset_info);
231
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
233
item_list.push_back(item_null);
235
/* Build "key", "key_len", and "ref" values and add them to item_list */
236
if (tab->ref.key_parts)
238
KEY *key_info= table->key_info+ tab->ref.key;
239
item_list.push_back(new Item_string(key_info->name,
240
strlen(key_info->name),
241
system_charset_info));
242
uint32_t length= int64_t2str(tab->ref.key_length, keylen_str_buf, 10) -
244
item_list.push_back(new Item_string(keylen_str_buf,
246
system_charset_info));
247
for (StoredKey **ref= tab->ref.key_copy; *ref; ref++)
251
tmp2.append((*ref)->name(),
252
strlen((*ref)->name()),
253
system_charset_info);
255
item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
257
else if (tab->type == AM_NEXT)
259
KEY *key_info=table->key_info+ tab->index;
260
item_list.push_back(new Item_string(key_info->name,
261
strlen(key_info->name),cs));
262
uint32_t length= int64_t2str(key_info->key_length, keylen_str_buf, 10) -
264
item_list.push_back(new Item_string(keylen_str_buf,
266
system_charset_info));
267
item_list.push_back(item_null);
269
else if (tab->select && tab->select->quick)
271
tab->select->quick->add_keys_and_lengths(&tmp2, &tmp3);
272
item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
273
item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
274
item_list.push_back(item_null);
278
item_list.push_back(item_null);
279
item_list.push_back(item_null);
280
item_list.push_back(item_null);
283
/* Add "rows" field to item_list. */
284
double examined_rows;
285
if (tab->select && tab->select->quick)
287
examined_rows= rows2double(tab->select->quick->records);
289
else if (tab->type == AM_NEXT || tab->type == AM_ALL)
291
examined_rows= rows2double(tab->limit ? tab->limit :
292
tab->table->cursor->records());
296
optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
297
examined_rows= cur_pos.getFanout();
300
item_list.push_back(new Item_int((int64_t) (uint64_t) examined_rows,
301
MY_INT64_NUM_DECIMAL_DIGITS));
303
/* Add "filtered" field to item_list. */
304
if (join->session->lex->describe & DESCRIBE_EXTENDED)
309
optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
310
f= static_cast<float>(100.0 * cur_pos.getFanout() / examined_rows);
312
item_list.push_back(new Item_float(f, 2));
315
/* Build "Extra" field and add it to item_list. */
316
bool key_read= table->key_read;
317
if ((tab->type == AM_NEXT || tab->type == AM_CONST) &&
318
table->covering_keys.test(tab->index))
320
if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT &&
321
! ((optimizer::QuickRorIntersectSelect *) tab->select->quick)->need_to_fetch_row)
325
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
326
else if (tab->packed_info & TAB_INFO_HAVE_VALUE)
328
if (tab->packed_info & TAB_INFO_USING_INDEX)
329
extra.append(STRING_WITH_LEN("; Using index"));
330
if (tab->packed_info & TAB_INFO_USING_WHERE)
331
extra.append(STRING_WITH_LEN("; Using where"));
332
if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL)
333
extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
334
/* Skip initial "; "*/
335
const char *str= extra.ptr();
336
uint32_t len= extra.length();
342
item_list.push_back(new Item_string(str, len, cs));
346
uint32_t keyno= MAX_KEY;
347
if (tab->ref.key_parts)
349
else if (tab->select && tab->select->quick)
350
keyno = tab->select->quick->index;
352
if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_UNION ||
353
quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT ||
354
quick_type == optimizer::QuickSelectInterface::QS_TYPE_INDEX_MERGE)
356
extra.append(STRING_WITH_LEN("; Using "));
357
tab->select->quick->add_info_string(&extra);
361
if (tab->use_quick == 2)
364
* To print out the bitset in tab->keys, we go through
365
* it 32 bits at a time. We need to do this to ensure
366
* that the to_ulong() method will not throw an
367
* out_of_range exception at runtime which would happen
368
* if the bitset we were working with was larger than 64
369
* bits on a 64-bit platform (for example).
375
for (uint32_t pos= 0; pos < tab->keys.size(); pos+= 32)
377
bitset<32> tmp(str, pos, 32);
379
s << uppercase << hex << tmp.to_ulong();
381
extra.append(STRING_WITH_LEN("; Range checked for each "
382
"record (index map: 0x"));
383
extra.append(s.str().c_str());
386
else if (tab->select->cond)
388
extra.append(STRING_WITH_LEN("; Using where"));
393
if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_GROUP_MIN_MAX)
394
extra.append(STRING_WITH_LEN("; Using index for group-by"));
396
extra.append(STRING_WITH_LEN("; Using index"));
398
if (table->reginfo.not_exists_optimize)
399
extra.append(STRING_WITH_LEN("; Not exists"));
404
extra.append(STRING_WITH_LEN("; Using temporary"));
409
extra.append(STRING_WITH_LEN("; Using filesort"));
411
if (distinct & test_all_bits(used_tables,session->used_tables))
412
extra.append(STRING_WITH_LEN("; Distinct"));
414
if (tab->insideout_match_tab)
416
extra.append(STRING_WITH_LEN("; LooseScan"));
419
for (uint32_t part= 0; part < tab->ref.key_parts; part++)
421
if (tab->ref.cond_guards[part])
423
extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
428
if (i > 0 && tab[-1].next_select == sub_select_cache)
429
extra.append(STRING_WITH_LEN("; Using join buffer"));
431
/* Skip initial "; "*/
432
const char *str= extra.ptr();
433
uint32_t len= extra.length();
439
item_list.push_back(new Item_string(str, len, cs));
441
// For next iteration
442
used_tables|=table->map;
443
if (result->send_data(item_list))
447
for (Select_Lex_Unit *unit= join->select_lex->first_inner_unit();
449
unit= unit->next_unit())
451
if (explainUnion(session, unit, result))
457
bool optimizer::ExplainPlan::explainUnion(Session *session,
458
Select_Lex_Unit *unit,
459
select_result *result)
462
Select_Lex *first= unit->first_select();
464
for (Select_Lex *sl= first;
466
sl= sl->next_select())
468
// drop UNCACHEABLE_EXPLAIN, because it is for internal usage only
469
uint8_t uncacheable= (sl->uncacheable & ~UNCACHEABLE_EXPLAIN);
470
if (&session->lex->select_lex == sl)
472
if (sl->first_inner_unit() || sl->next_select())
474
sl->type.assign("PRIMARY");
478
sl->type.assign("SIMPLE");
485
if (sl->linkage == DERIVED_TABLE_TYPE)
487
sl->type.assign("DERIVED");
491
if (uncacheable & UNCACHEABLE_DEPENDENT)
493
sl->type.assign("DEPENDENT SUBQUERY");
499
sl->type.assign("UNCACHEABLE SUBQUERY");
503
sl->type.assign("SUBQUERY");
510
if (uncacheable & UNCACHEABLE_DEPENDENT)
512
sl->type.assign("DEPENDENT UNION");
518
sl->type.assign("UNCACHEABLE_UNION");
522
sl->type.assign("UNION");
527
sl->options|= SELECT_DESCRIBE;
530
if (unit->is_union())
532
unit->fake_select_lex->select_number= UINT_MAX; // just for initialization
533
unit->fake_select_lex->type.assign("UNION RESULT");
534
unit->fake_select_lex->options|= SELECT_DESCRIBE;
535
if (! (res= unit->prepare(session, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
539
res|= unit->cleanup();
543
session->lex->current_select= first;
544
unit->set_limit(unit->global_parameters);
545
res= mysql_select(session,
546
&first->ref_pointer_array,
547
(TableList*) first->table_list.first,
551
first->order_list.elements + first->group_list.elements,
552
(order_st*) first->order_list.first,
553
(order_st*) first->group_list.first,
555
first->options | session->options | SELECT_DESCRIBE,
560
return (res || session->is_error());