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"
40
static const string access_method_str[]=
57
static const string select_type_str[]=
63
"UNCACHEABLE SUBQUERY",
71
void optimizer::ExplainPlan::printPlan()
73
List<Item> field_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;
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;
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()
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(),
95
for (uint32_t i= 0; i < 7; i++)
96
item_list.push_back(item_null);
98
if (join->session->lex->describe & DESCRIBE_EXTENDED)
99
item_list.push_back(item_null);
101
item_list.push_back(new Item_string(message,strlen(message),cs));
102
if (result->send_data(item_list))
105
else if (join->select_lex == join->unit->fake_select_lex)
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
114
char table_name_buffer[NAME_LEN];
117
item_list.push_back(new Item_null);
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(),
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())
130
lastop= snprintf(table_name_buffer + len, NAME_LEN - len,
131
"%u,", sl->select_number);
133
if (sl || len + lastop >= NAME_LEN)
135
memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1);
141
table_name_buffer[len - 1]= '>'; // change ',' to '>'
143
item_list.push_back(new Item_string(table_name_buffer, len, cs));
146
item_list.push_back(new Item_string(access_method_str[AM_ALL].c_str(),
147
access_method_str[AM_ALL].length(),
150
item_list.push_back(item_null);
152
item_list.push_back(item_null);
154
item_list.push_back(item_null);
156
item_list.push_back(item_null);
158
if (join->session->lex->describe & DESCRIBE_EXTENDED)
159
item_list.push_back(item_null);
161
item_list.push_back(item_null);
163
if (join->unit->global_parameters->order_list.first)
164
item_list.push_back(new Item_string("Using filesort",
168
item_list.push_back(new Item_string("", 0, cs));
170
if (result->send_data(item_list))
175
table_map used_tables= 0;
176
for (uint32_t i= 0; i < join->tables; i++)
178
JoinTable *tab= join->join_tab + i;
179
Table *table= tab->table;
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);
196
item_list.push_back(new Item_uint((uint32_t)
197
join->select_lex->select_number));
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(),
202
if (tab->type == AM_ALL && tab->select && tab->select->quick)
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;
210
tab->type = AM_RANGE;
213
if (table->derived_select_number)
215
/* Derived table name generation */
216
int len= snprintf(table_name_buffer,
217
sizeof(table_name_buffer)-1,
219
table->derived_select_number);
220
item_list.push_back(new Item_string(table_name_buffer, len, cs));
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),
230
item_list.push_back(new Item_string(access_method_str[tab->type].c_str(),
231
access_method_str[tab->type].length(),
233
/* Build "possible_keys" value and add it to item_list */
236
for (uint32_t j= 0; j < table->s->keys; j++)
238
if (tab->keys.test(j))
242
tmp1.append(table->key_info[j].name,
243
strlen(table->key_info[j].name),
244
system_charset_info);
249
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
251
item_list.push_back(item_null);
253
/* Build "key", "key_len", and "ref" values and add them to item_list */
254
if (tab->ref.key_parts)
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) -
262
item_list.push_back(new Item_string(keylen_str_buf,
264
system_charset_info));
265
for (StoredKey **ref= tab->ref.key_copy; *ref; ref++)
269
tmp2.append((*ref)->name(),
270
strlen((*ref)->name()),
271
system_charset_info);
273
item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
275
else if (tab->type == AM_NEXT)
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) -
282
item_list.push_back(new Item_string(keylen_str_buf,
284
system_charset_info));
285
item_list.push_back(item_null);
287
else if (tab->select && tab->select->quick)
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);
296
item_list.push_back(item_null);
297
item_list.push_back(item_null);
298
item_list.push_back(item_null);
301
/* Add "rows" field to item_list. */
302
double examined_rows;
303
if (tab->select && tab->select->quick)
305
examined_rows= rows2double(tab->select->quick->records);
307
else if (tab->type == AM_NEXT || tab->type == AM_ALL)
309
examined_rows= rows2double(tab->limit ? tab->limit :
310
tab->table->cursor->records());
314
optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
315
examined_rows= cur_pos.getFanout();
318
item_list.push_back(new Item_int((int64_t) (uint64_t) examined_rows,
319
MY_INT64_NUM_DECIMAL_DIGITS));
321
/* Add "filtered" field to item_list. */
322
if (join->session->lex->describe & DESCRIBE_EXTENDED)
327
optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
328
f= static_cast<float>(100.0 * cur_pos.getFanout() / examined_rows);
330
item_list.push_back(new Item_float(f, 2));
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))
338
if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT &&
339
! ((optimizer::QuickRorIntersectSelect *) tab->select->quick)->need_to_fetch_row)
343
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
344
else if (tab->packed_info & TAB_INFO_HAVE_VALUE)
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();
360
item_list.push_back(new Item_string(str, len, cs));
364
uint32_t keyno= MAX_KEY;
365
if (tab->ref.key_parts)
367
else if (tab->select && tab->select->quick)
368
keyno = tab->select->quick->index;
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)
374
extra.append(STRING_WITH_LEN("; Using "));
375
tab->select->quick->add_info_string(&extra);
379
if (tab->use_quick == 2)
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).
393
for (uint32_t pos= 0; pos < tab->keys.size(); pos+= 32)
395
bitset<32> tmp(str, pos, 32);
397
s << uppercase << hex << tmp.to_ulong();
399
extra.append(STRING_WITH_LEN("; Range checked for each "
400
"record (index map: 0x"));
401
extra.append(s.str().c_str());
404
else if (tab->select->cond)
406
extra.append(STRING_WITH_LEN("; Using where"));
411
if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_GROUP_MIN_MAX)
412
extra.append(STRING_WITH_LEN("; Using index for group-by"));
414
extra.append(STRING_WITH_LEN("; Using index"));
416
if (table->reginfo.not_exists_optimize)
417
extra.append(STRING_WITH_LEN("; Not exists"));
422
extra.append(STRING_WITH_LEN("; Using temporary"));
427
extra.append(STRING_WITH_LEN("; Using filesort"));
429
if (distinct & test_all_bits(used_tables,session->used_tables))
430
extra.append(STRING_WITH_LEN("; Distinct"));
432
if (tab->insideout_match_tab)
434
extra.append(STRING_WITH_LEN("; LooseScan"));
437
for (uint32_t part= 0; part < tab->ref.key_parts; part++)
439
if (tab->ref.cond_guards[part])
441
extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
446
if (i > 0 && tab[-1].next_select == sub_select_cache)
447
extra.append(STRING_WITH_LEN("; Using join buffer"));
449
/* Skip initial "; "*/
450
const char *str= extra.ptr();
451
uint32_t len= extra.length();
457
item_list.push_back(new Item_string(str, len, cs));
459
// For next iteration
460
used_tables|=table->map;
461
if (result->send_data(item_list))
465
for (Select_Lex_Unit *unit= join->select_lex->first_inner_unit();
467
unit= unit->next_unit())
469
if (explainUnion(session, unit, result))
475
bool optimizer::ExplainPlan::explainUnion(Session *session,
476
Select_Lex_Unit *unit,
477
select_result *result)
480
Select_Lex *first= unit->first_select();
482
for (Select_Lex *sl= first;
484
sl= sl->next_select())
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)
490
if (sl->first_inner_unit() || sl->next_select())
492
sl->type= optimizer::ST_PRIMARY;
496
sl->type= optimizer::ST_SIMPLE;
503
if (sl->linkage == DERIVED_TABLE_TYPE)
505
sl->type= optimizer::ST_DERIVED;
509
if (uncacheable & UNCACHEABLE_DEPENDENT)
511
sl->type= optimizer::ST_DEPENDENT_SUBQUERY;
517
sl->type= optimizer::ST_UNCACHEABLE_SUBQUERY;
521
sl->type= optimizer::ST_SUBQUERY;
528
if (uncacheable & UNCACHEABLE_DEPENDENT)
530
sl->type= optimizer::ST_DEPENDENT_UNION;
536
sl->type= optimizer::ST_UNCACHEABLE_UNION;
540
sl->type= optimizer::ST_UNION;
545
sl->options|= SELECT_DESCRIBE;
548
if (unit->is_union())
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)))
557
res|= unit->cleanup();
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,
569
first->order_list.elements + first->group_list.elements,
570
(order_st*) first->order_list.first,
571
(order_st*) first->group_list.first,
573
first->options | session->options | SELECT_DESCRIBE,
578
return (res || session->is_error());
581
} /* namespace drizzled */