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
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"
36
using namespace drizzled;
38
static const string access_method_str[]=
55
static const string select_type_str[]=
61
"UNCACHEABLE SUBQUERY",
69
void optimizer::ExplainPlan::printPlan()
71
List<Item> field_list;
73
Session *session= join->session;
74
select_result *result= join->result;
75
Item *item_null= new Item_null();
76
const CHARSET_INFO * const cs= system_charset_info;
78
/* Don't log this into the slow query log */
79
session->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
80
join->unit->offset_limit_cnt= 0;
83
NOTE: the number/types of items pushed into item_list must be in sync with
84
EXPLAIN column types as they're "defined" in Session::send_explain_fields()
88
item_list.push_back(new Item_int((int32_t)
89
join->select_lex->select_number));
90
item_list.push_back(new Item_string(select_type_str[join->select_lex->type].c_str(),
91
select_type_str[join->select_lex->type].length(),
93
for (uint32_t i= 0; i < 7; i++)
94
item_list.push_back(item_null);
96
if (join->session->lex->describe & DESCRIBE_EXTENDED)
97
item_list.push_back(item_null);
99
item_list.push_back(new Item_string(message,strlen(message),cs));
100
if (result->send_data(item_list))
103
else if (join->select_lex == join->unit->fake_select_lex)
106
here we assume that the query will return at least two rows, so we
107
show "filesort" in EXPLAIN. Of course, sometimes we'll be wrong
108
and no filesort will be actually done, but executing all selects in
109
the UNION to provide precise EXPLAIN information will hardly be
112
char table_name_buffer[NAME_LEN];
115
item_list.push_back(new Item_null);
117
item_list.push_back(new Item_string(select_type_str[join->select_lex->type].c_str(),
118
select_type_str[join->select_lex->type].length(),
122
Select_Lex *sl= join->unit->first_select();
123
uint32_t len= 6, lastop= 0;
124
memcpy(table_name_buffer, STRING_WITH_LEN("<union"));
125
for (; sl && len + lastop + 5 < NAME_LEN; sl= sl->next_select())
128
lastop= snprintf(table_name_buffer + len, NAME_LEN - len,
129
"%u,", sl->select_number);
131
if (sl || len + lastop >= NAME_LEN)
133
memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1);
139
table_name_buffer[len - 1]= '>'; // change ',' to '>'
141
item_list.push_back(new Item_string(table_name_buffer, len, cs));
144
item_list.push_back(new Item_string(access_method_str[AM_ALL].c_str(),
145
access_method_str[AM_ALL].length(),
148
item_list.push_back(item_null);
150
item_list.push_back(item_null);
152
item_list.push_back(item_null);
154
item_list.push_back(item_null);
156
if (join->session->lex->describe & DESCRIBE_EXTENDED)
157
item_list.push_back(item_null);
159
item_list.push_back(item_null);
161
if (join->unit->global_parameters->order_list.first)
162
item_list.push_back(new Item_string("Using filesort",
166
item_list.push_back(new Item_string("", 0, cs));
168
if (result->send_data(item_list))
173
table_map used_tables= 0;
174
for (uint32_t i= 0; i < join->tables; i++)
176
JoinTable *tab= join->join_tab + i;
177
Table *table= tab->table;
179
char buff1[512], buff2[512], buff3[512];
180
char keylen_str_buf[64];
181
String extra(buff, sizeof(buff),cs);
182
char table_name_buffer[NAME_LEN];
183
String tmp1(buff1,sizeof(buff1),cs);
184
String tmp2(buff2,sizeof(buff2),cs);
185
String tmp3(buff3,sizeof(buff3),cs);
194
item_list.push_back(new Item_uint((uint32_t)
195
join->select_lex->select_number));
197
item_list.push_back(new Item_string(select_type_str[join->select_lex->type].c_str(),
198
select_type_str[join->select_lex->type].length(),
200
if (tab->type == AM_ALL && tab->select && tab->select->quick)
202
quick_type= tab->select->quick->get_type();
203
if ((quick_type == optimizer::QuickSelectInterface::QS_TYPE_INDEX_MERGE) ||
204
(quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT) ||
205
(quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_UNION))
206
tab->type = AM_INDEX_MERGE;
208
tab->type = AM_RANGE;
211
if (table->derived_select_number)
213
/* Derived table name generation */
214
int len= snprintf(table_name_buffer,
215
sizeof(table_name_buffer)-1,
217
table->derived_select_number);
218
item_list.push_back(new Item_string(table_name_buffer, len, cs));
222
TableList *real_table= table->pos_in_table_list;
223
item_list.push_back(new Item_string(real_table->alias,
224
strlen(real_table->alias),
228
item_list.push_back(new Item_string(access_method_str[tab->type].c_str(),
229
access_method_str[tab->type].length(),
231
/* Build "possible_keys" value and add it to item_list */
234
for (uint32_t j= 0; j < table->s->keys; j++)
236
if (tab->keys.test(j))
240
tmp1.append(table->key_info[j].name,
241
strlen(table->key_info[j].name),
242
system_charset_info);
247
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
249
item_list.push_back(item_null);
251
/* Build "key", "key_len", and "ref" values and add them to item_list */
252
if (tab->ref.key_parts)
254
KEY *key_info= table->key_info+ tab->ref.key;
255
item_list.push_back(new Item_string(key_info->name,
256
strlen(key_info->name),
257
system_charset_info));
258
uint32_t length= int64_t2str(tab->ref.key_length, keylen_str_buf, 10) -
260
item_list.push_back(new Item_string(keylen_str_buf,
262
system_charset_info));
263
for (StoredKey **ref= tab->ref.key_copy; *ref; ref++)
267
tmp2.append((*ref)->name(),
268
strlen((*ref)->name()),
269
system_charset_info);
271
item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
273
else if (tab->type == AM_NEXT)
275
KEY *key_info=table->key_info+ tab->index;
276
item_list.push_back(new Item_string(key_info->name,
277
strlen(key_info->name),cs));
278
uint32_t length= int64_t2str(key_info->key_length, keylen_str_buf, 10) -
280
item_list.push_back(new Item_string(keylen_str_buf,
282
system_charset_info));
283
item_list.push_back(item_null);
285
else if (tab->select && tab->select->quick)
287
tab->select->quick->add_keys_and_lengths(&tmp2, &tmp3);
288
item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
289
item_list.push_back(new Item_string(tmp3.ptr(),tmp3.length(),cs));
290
item_list.push_back(item_null);
294
item_list.push_back(item_null);
295
item_list.push_back(item_null);
296
item_list.push_back(item_null);
299
/* Add "rows" field to item_list. */
300
double examined_rows;
301
if (tab->select && tab->select->quick)
303
examined_rows= rows2double(tab->select->quick->records);
305
else if (tab->type == AM_NEXT || tab->type == AM_ALL)
307
examined_rows= rows2double(tab->limit ? tab->limit :
308
tab->table->cursor->records());
312
optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
313
examined_rows= cur_pos.getFanout();
316
item_list.push_back(new Item_int((int64_t) (uint64_t) examined_rows,
317
MY_INT64_NUM_DECIMAL_DIGITS));
319
/* Add "filtered" field to item_list. */
320
if (join->session->lex->describe & DESCRIBE_EXTENDED)
325
optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
326
f= static_cast<float>(100.0 * cur_pos.getFanout() / examined_rows);
328
item_list.push_back(new Item_float(f, 2));
331
/* Build "Extra" field and add it to item_list. */
332
bool key_read= table->key_read;
333
if ((tab->type == AM_NEXT || tab->type == AM_CONST) &&
334
table->covering_keys.test(tab->index))
336
if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT &&
337
! ((optimizer::QuickRorIntersectSelect *) tab->select->quick)->need_to_fetch_row)
341
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
342
else if (tab->packed_info & TAB_INFO_HAVE_VALUE)
344
if (tab->packed_info & TAB_INFO_USING_INDEX)
345
extra.append(STRING_WITH_LEN("; Using index"));
346
if (tab->packed_info & TAB_INFO_USING_WHERE)
347
extra.append(STRING_WITH_LEN("; Using where"));
348
if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL)
349
extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
350
/* Skip initial "; "*/
351
const char *str= extra.ptr();
352
uint32_t len= extra.length();
358
item_list.push_back(new Item_string(str, len, cs));
362
uint32_t keyno= MAX_KEY;
363
if (tab->ref.key_parts)
365
else if (tab->select && tab->select->quick)
366
keyno = tab->select->quick->index;
368
if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_UNION ||
369
quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT ||
370
quick_type == optimizer::QuickSelectInterface::QS_TYPE_INDEX_MERGE)
372
extra.append(STRING_WITH_LEN("; Using "));
373
tab->select->quick->add_info_string(&extra);
377
if (tab->use_quick == 2)
380
* To print out the bitset in tab->keys, we go through
381
* it 32 bits at a time. We need to do this to ensure
382
* that the to_ulong() method will not throw an
383
* out_of_range exception at runtime which would happen
384
* if the bitset we were working with was larger than 64
385
* bits on a 64-bit platform (for example).
391
for (uint32_t pos= 0; pos < tab->keys.size(); pos+= 32)
393
bitset<32> tmp(str, pos, 32);
395
s << uppercase << hex << tmp.to_ulong();
397
extra.append(STRING_WITH_LEN("; Range checked for each "
398
"record (index map: 0x"));
399
extra.append(s.str().c_str());
402
else if (tab->select->cond)
404
extra.append(STRING_WITH_LEN("; Using where"));
409
if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_GROUP_MIN_MAX)
410
extra.append(STRING_WITH_LEN("; Using index for group-by"));
412
extra.append(STRING_WITH_LEN("; Using index"));
414
if (table->reginfo.not_exists_optimize)
415
extra.append(STRING_WITH_LEN("; Not exists"));
420
extra.append(STRING_WITH_LEN("; Using temporary"));
425
extra.append(STRING_WITH_LEN("; Using filesort"));
427
if (distinct & test_all_bits(used_tables,session->used_tables))
428
extra.append(STRING_WITH_LEN("; Distinct"));
430
if (tab->insideout_match_tab)
432
extra.append(STRING_WITH_LEN("; LooseScan"));
435
for (uint32_t part= 0; part < tab->ref.key_parts; part++)
437
if (tab->ref.cond_guards[part])
439
extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
444
if (i > 0 && tab[-1].next_select == sub_select_cache)
445
extra.append(STRING_WITH_LEN("; Using join buffer"));
447
/* Skip initial "; "*/
448
const char *str= extra.ptr();
449
uint32_t len= extra.length();
455
item_list.push_back(new Item_string(str, len, cs));
457
// For next iteration
458
used_tables|=table->map;
459
if (result->send_data(item_list))
463
for (Select_Lex_Unit *unit= join->select_lex->first_inner_unit();
465
unit= unit->next_unit())
467
if (explainUnion(session, unit, result))
473
bool optimizer::ExplainPlan::explainUnion(Session *session,
474
Select_Lex_Unit *unit,
475
select_result *result)
478
Select_Lex *first= unit->first_select();
480
for (Select_Lex *sl= first;
482
sl= sl->next_select())
484
// drop UNCACHEABLE_EXPLAIN, because it is for internal usage only
485
uint8_t uncacheable= (sl->uncacheable & ~UNCACHEABLE_EXPLAIN);
486
if (&session->lex->select_lex == sl)
488
if (sl->first_inner_unit() || sl->next_select())
490
sl->type= optimizer::ST_PRIMARY;
494
sl->type= optimizer::ST_SIMPLE;
501
if (sl->linkage == DERIVED_TABLE_TYPE)
503
sl->type= optimizer::ST_DERIVED;
507
if (uncacheable & UNCACHEABLE_DEPENDENT)
509
sl->type= optimizer::ST_DEPENDENT_SUBQUERY;
515
sl->type= optimizer::ST_UNCACHEABLE_SUBQUERY;
519
sl->type= optimizer::ST_SUBQUERY;
526
if (uncacheable & UNCACHEABLE_DEPENDENT)
528
sl->type= optimizer::ST_DEPENDENT_UNION;
534
sl->type= optimizer::ST_UNCACHEABLE_UNION;
538
sl->type= optimizer::ST_UNION;
543
sl->options|= SELECT_DESCRIBE;
546
if (unit->is_union())
548
unit->fake_select_lex->select_number= UINT_MAX; // just for initialization
549
unit->fake_select_lex->type= optimizer::ST_UNION_RESULT;
550
unit->fake_select_lex->options|= SELECT_DESCRIBE;
551
if (! (res= unit->prepare(session, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
555
res|= unit->cleanup();
559
session->lex->current_select= first;
560
unit->set_limit(unit->global_parameters);
561
res= mysql_select(session,
562
&first->ref_pointer_array,
563
(TableList*) first->table_list.first,
567
first->order_list.elements + first->group_list.elements,
568
(order_st*) first->order_list.first,
569
(order_st*) first->group_list.first,
571
first->options | session->options | SELECT_DESCRIBE,
576
return (res || session->is_error());