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, Inc.
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/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"
43
static const string access_method_str[]=
60
static const string select_type_str[]=
66
"UNCACHEABLE SUBQUERY",
74
void optimizer::ExplainPlan::printPlan()
76
List<Item> field_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;
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;
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()
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(),
98
for (uint32_t i= 0; i < 7; i++)
99
item_list.push_back(item_null);
101
if (join->session->lex->describe & DESCRIBE_EXTENDED)
102
item_list.push_back(item_null);
104
item_list.push_back(new Item_string(message,strlen(message),cs));
105
if (result->send_data(item_list))
108
else if (join->select_lex == join->unit->fake_select_lex)
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
117
char table_name_buffer[NAME_LEN];
120
item_list.push_back(new Item_null);
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(),
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())
133
lastop= snprintf(table_name_buffer + len, NAME_LEN - len,
134
"%u,", sl->select_number);
136
if (sl || len + lastop >= NAME_LEN)
138
memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1);
144
table_name_buffer[len - 1]= '>'; // change ',' to '>'
146
item_list.push_back(new Item_string(table_name_buffer, len, cs));
149
item_list.push_back(new Item_string(access_method_str[AM_ALL].c_str(),
150
access_method_str[AM_ALL].length(),
153
item_list.push_back(item_null);
155
item_list.push_back(item_null);
157
item_list.push_back(item_null);
159
item_list.push_back(item_null);
161
if (join->session->lex->describe & DESCRIBE_EXTENDED)
162
item_list.push_back(item_null);
164
item_list.push_back(item_null);
166
if (join->unit->global_parameters->order_list.first)
167
item_list.push_back(new Item_string("Using filesort",
171
item_list.push_back(new Item_string("", 0, cs));
173
if (result->send_data(item_list))
178
table_map used_tables= 0;
179
for (uint32_t i= 0; i < join->tables; i++)
181
JoinTable *tab= join->join_tab + i;
182
Table *table= tab->table;
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);
199
item_list.push_back(new Item_uint((uint32_t)
200
join->select_lex->select_number));
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(),
205
if (tab->type == AM_ALL && tab->select && tab->select->quick)
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;
213
tab->type = AM_RANGE;
216
if (table->derived_select_number)
218
/* Derived table name generation */
219
int len= snprintf(table_name_buffer,
220
sizeof(table_name_buffer)-1,
222
table->derived_select_number);
223
item_list.push_back(new Item_string(table_name_buffer, len, cs));
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),
233
item_list.push_back(new Item_string(access_method_str[tab->type].c_str(),
234
access_method_str[tab->type].length(),
236
/* Build "possible_keys" value and add it to item_list */
239
for (uint32_t j= 0; j < table->getShare()->sizeKeys(); j++)
241
if (tab->keys.test(j))
245
tmp1.append(table->key_info[j].name,
246
strlen(table->key_info[j].name),
247
system_charset_info);
252
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
254
item_list.push_back(item_null);
256
/* Build "key", "key_len", and "ref" values and add them to item_list */
257
if (tab->ref.key_parts)
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) -
265
item_list.push_back(new Item_string(keylen_str_buf,
267
system_charset_info));
268
for (StoredKey **ref= tab->ref.key_copy; *ref; ref++)
272
tmp2.append((*ref)->name(),
273
strlen((*ref)->name()),
274
system_charset_info);
276
item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),cs));
278
else if (tab->type == AM_NEXT)
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) -
285
item_list.push_back(new Item_string(keylen_str_buf,
287
system_charset_info));
288
item_list.push_back(item_null);
290
else if (tab->select && tab->select->quick)
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);
299
item_list.push_back(item_null);
300
item_list.push_back(item_null);
301
item_list.push_back(item_null);
304
/* Add "rows" field to item_list. */
305
double examined_rows;
306
if (tab->select && tab->select->quick)
308
examined_rows= rows2double(tab->select->quick->records);
310
else if (tab->type == AM_NEXT || tab->type == AM_ALL)
312
examined_rows= rows2double(tab->limit ? tab->limit :
313
tab->table->cursor->records());
317
optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
318
examined_rows= cur_pos.getFanout();
321
item_list.push_back(new Item_int((int64_t) (uint64_t) examined_rows,
322
MY_INT64_NUM_DECIMAL_DIGITS));
324
/* Add "filtered" field to item_list. */
325
if (join->session->lex->describe & DESCRIBE_EXTENDED)
330
optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
331
f= static_cast<float>(100.0 * cur_pos.getFanout() / examined_rows);
333
item_list.push_back(new Item_float(f, 2));
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))
341
if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT &&
342
! ((optimizer::QuickRorIntersectSelect *) tab->select->quick)->need_to_fetch_row)
346
item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs));
347
else if (tab->packed_info & TAB_INFO_HAVE_VALUE)
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();
363
item_list.push_back(new Item_string(str, len, cs));
367
uint32_t keyno= MAX_KEY;
368
if (tab->ref.key_parts)
370
else if (tab->select && tab->select->quick)
371
keyno = tab->select->quick->index;
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)
377
extra.append(STRING_WITH_LEN("; Using "));
378
tab->select->quick->add_info_string(&extra);
382
if (tab->use_quick == 2)
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).
396
for (uint32_t pos= 0; pos < tab->keys.size(); pos+= 32)
398
bitset<32> tmp(str, pos, 32);
400
s << uppercase << hex << tmp.to_ulong();
402
extra.append(STRING_WITH_LEN("; Range checked for each "
403
"record (index map: 0x"));
404
extra.append(s.str().c_str());
407
else if (tab->select->cond)
409
extra.append(STRING_WITH_LEN("; Using where"));
414
if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_GROUP_MIN_MAX)
415
extra.append(STRING_WITH_LEN("; Using index for group-by"));
417
extra.append(STRING_WITH_LEN("; Using index"));
419
if (table->reginfo.not_exists_optimize)
420
extra.append(STRING_WITH_LEN("; Not exists"));
425
extra.append(STRING_WITH_LEN("; Using temporary"));
430
extra.append(STRING_WITH_LEN("; Using filesort"));
432
if (distinct & test_all_bits(used_tables,session->used_tables))
433
extra.append(STRING_WITH_LEN("; Distinct"));
435
if (tab->insideout_match_tab)
437
extra.append(STRING_WITH_LEN("; LooseScan"));
440
for (uint32_t part= 0; part < tab->ref.key_parts; part++)
442
if (tab->ref.cond_guards[part])
444
extra.append(STRING_WITH_LEN("; Full scan on NULL key"));
449
if (i > 0 && tab[-1].next_select == sub_select_cache)
450
extra.append(STRING_WITH_LEN("; Using join buffer"));
452
/* Skip initial "; "*/
453
const char *str= extra.ptr();
454
uint32_t len= extra.length();
460
item_list.push_back(new Item_string(str, len, cs));
462
// For next iteration
463
used_tables|=table->map;
464
if (result->send_data(item_list))
468
for (Select_Lex_Unit *unit= join->select_lex->first_inner_unit();
470
unit= unit->next_unit())
472
if (explainUnion(session, unit, result))
478
bool optimizer::ExplainPlan::explainUnion(Session *session,
479
Select_Lex_Unit *unit,
480
select_result *result)
483
Select_Lex *first= unit->first_select();
485
for (Select_Lex *sl= first;
487
sl= sl->next_select())
489
// drop UNCACHEABLE_EXPLAIN, because it is for internal usage only
490
sl->uncacheable.reset(UNCACHEABLE_EXPLAIN);
491
if (&session->lex->select_lex == sl)
493
if (sl->first_inner_unit() || sl->next_select())
495
sl->type= optimizer::ST_PRIMARY;
499
sl->type= optimizer::ST_SIMPLE;
506
if (sl->linkage == DERIVED_TABLE_TYPE)
508
sl->type= optimizer::ST_DERIVED;
512
if (sl->uncacheable.test(UNCACHEABLE_DEPENDENT))
514
sl->type= optimizer::ST_DEPENDENT_SUBQUERY;
518
if (sl->uncacheable.any())
520
sl->type= optimizer::ST_UNCACHEABLE_SUBQUERY;
524
sl->type= optimizer::ST_SUBQUERY;
531
if (sl->uncacheable.test(UNCACHEABLE_DEPENDENT))
533
sl->type= optimizer::ST_DEPENDENT_UNION;
537
if (sl->uncacheable.any())
539
sl->type= optimizer::ST_UNCACHEABLE_UNION;
543
sl->type= optimizer::ST_UNION;
548
sl->options|= SELECT_DESCRIBE;
551
if (unit->is_union())
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)))
560
res|= unit->cleanup();
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,
572
first->order_list.elements + first->group_list.elements,
573
(Order*) first->order_list.first,
574
(Order*) first->group_list.first,
576
first->options | session->options | SELECT_DESCRIBE,
581
return (res || session->is_error());
584
} /* namespace drizzled */