00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021
00022 #include <drizzled/session.h>
00023 #include <drizzled/item/uint.h>
00024 #include <drizzled/item/float.h>
00025 #include <drizzled/item/string.h>
00026 #include <drizzled/optimizer/explain_plan.h>
00027 #include <drizzled/optimizer/position.h>
00028 #include <drizzled/optimizer/quick_ror_intersect_select.h>
00029 #include <drizzled/optimizer/range.h>
00030 #include <drizzled/sql_select.h>
00031 #include <drizzled/join.h>
00032 #include <drizzled/internal/m_string.h>
00033 #include <drizzled/select_result.h>
00034 #include <drizzled/sql_lex.h>
00035
00036 #include <cstdio>
00037 #include <string>
00038 #include <sstream>
00039 #include <bitset>
00040
00041 using namespace std;
00042
00043 namespace drizzled
00044 {
00045
00046 static const string access_method_str[]=
00047 {
00048 "UNKNOWN",
00049 "system",
00050 "const",
00051 "eq_ref",
00052 "ref",
00053 "MAYBE_REF",
00054 "ALL",
00055 "range",
00056 "index",
00057 "ref_or_null",
00058 "unique_subquery",
00059 "index_subquery",
00060 "index_merge"
00061 };
00062
00063 static const string select_type_str[]=
00064 {
00065 "PRIMARY",
00066 "SIMPLE",
00067 "DERIVED",
00068 "DEPENDENT SUBQUERY",
00069 "UNCACHEABLE SUBQUERY",
00070 "SUBQUERY",
00071 "DEPENDENT UNION",
00072 "UNCACHEABLE_UNION",
00073 "UNION",
00074 "UNION RESULT"
00075 };
00076
00077 void optimizer::ExplainPlan::printPlan()
00078 {
00079 List<Item> item_list;
00080 Session *session= join->session;
00081 select_result *result= join->result;
00082 Item *item_null= new Item_null();
00083 const charset_info_st * const cs= system_charset_info;
00084 int quick_type;
00085
00086 session->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
00087 join->unit->offset_limit_cnt= 0;
00088
00089
00090
00091
00092
00093 if (message)
00094 {
00095 item_list.push_back(new Item_int((int32_t)join->select_lex->select_number));
00096 item_list.push_back(new Item_string(select_type_str[join->select_lex->type], cs));
00097 for (uint32_t i= 0; i < 7; i++)
00098 item_list.push_back(item_null);
00099
00100 if (join->session->lex().describe & DESCRIBE_EXTENDED)
00101 item_list.push_back(item_null);
00102
00103 item_list.push_back(new Item_string(str_ref(message), cs));
00104 if (result->send_data(item_list))
00105 join->error= 1;
00106 }
00107 else if (join->select_lex == join->unit->fake_select_lex)
00108 {
00109
00110
00111
00112
00113
00114
00115
00116 char table_name_buffer[NAME_LEN];
00117 item_list.clear();
00118
00119 item_list.push_back(new Item_null);
00120
00121 item_list.push_back(new Item_string(select_type_str[join->select_lex->type], cs));
00122
00123 {
00124 Select_Lex *sl= join->unit->first_select();
00125 uint32_t len= 6, lastop= 0;
00126 memcpy(table_name_buffer, STRING_WITH_LEN("<union"));
00127 for (; sl && len + lastop + 5 < NAME_LEN; sl= sl->next_select())
00128 {
00129 len+= lastop;
00130 lastop= snprintf(table_name_buffer + len, NAME_LEN - len,
00131 "%u,", sl->select_number);
00132 }
00133 if (sl || len + lastop >= NAME_LEN)
00134 {
00135 memcpy(table_name_buffer + len, STRING_WITH_LEN("...>") + 1);
00136 len+= 4;
00137 }
00138 else
00139 {
00140 len+= lastop;
00141 table_name_buffer[len - 1]= '>';
00142 }
00143 item_list.push_back(new Item_string(table_name_buffer, len, cs));
00144 }
00145
00146 item_list.push_back(new Item_string(access_method_str[AM_ALL], cs));
00147
00148 item_list.push_back(item_null);
00149
00150 item_list.push_back(item_null);
00151
00152 item_list.push_back(item_null);
00153
00154 item_list.push_back(item_null);
00155
00156 if (join->session->lex().describe & DESCRIBE_EXTENDED)
00157 item_list.push_back(item_null);
00158
00159 item_list.push_back(item_null);
00160
00161 if (join->unit->global_parameters->order_list.first)
00162 item_list.push_back(new Item_string(str_ref("Using filesort"), cs));
00163 else
00164 item_list.push_back(new Item_string(str_ref(""), cs));
00165
00166 if (result->send_data(item_list))
00167 join->error= 1;
00168 }
00169 else
00170 {
00171 table_map used_tables= 0;
00172 for (uint32_t i= 0; i < join->tables; i++)
00173 {
00174 JoinTable *tab= join->join_tab + i;
00175 Table *table= tab->table;
00176 char keylen_str_buf[64];
00177 string extra;
00178 char table_name_buffer[NAME_LEN];
00179 string tmp1;
00180 string tmp2;
00181 string tmp3;
00182
00183 quick_type= -1;
00184 item_list.clear();
00185
00186 item_list.push_back(new Item_uint((uint32_t)join->select_lex->select_number));
00187
00188 item_list.push_back(new Item_string(select_type_str[join->select_lex->type], cs));
00189 if (tab->type == AM_ALL && tab->select && tab->select->quick)
00190 {
00191 quick_type= tab->select->quick->get_type();
00192 if ((quick_type == optimizer::QuickSelectInterface::QS_TYPE_INDEX_MERGE) ||
00193 (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT) ||
00194 (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_UNION))
00195 tab->type = AM_INDEX_MERGE;
00196 else
00197 tab->type = AM_RANGE;
00198 }
00199
00200 if (table->derived_select_number)
00201 {
00202
00203 int len= snprintf(table_name_buffer,
00204 sizeof(table_name_buffer)-1,
00205 "<derived%u>",
00206 table->derived_select_number);
00207 item_list.push_back(new Item_string(table_name_buffer, len, cs));
00208 }
00209 else
00210 {
00211 TableList *real_table= table->pos_in_table_list;
00212 item_list.push_back(new Item_string(str_ref(real_table->alias), cs));
00213 }
00214
00215 item_list.push_back(new Item_string(access_method_str[tab->type], cs));
00216
00217 if (tab->keys.any())
00218 {
00219 for (uint32_t j= 0; j < table->getShare()->sizeKeys(); j++)
00220 {
00221 if (tab->keys.test(j))
00222 {
00223 if (tmp1.length())
00224 tmp1.append(",");
00225 tmp1.append(table->key_info[j].name,
00226 strlen(table->key_info[j].name));
00227 }
00228 }
00229 }
00230 if (tmp1.length())
00231 item_list.push_back(new Item_string(tmp1, cs));
00232 else
00233 item_list.push_back(item_null);
00234
00235
00236 if (tab->ref.key_parts)
00237 {
00238 KeyInfo *key_info= table->key_info+ tab->ref.key;
00239 item_list.push_back(new Item_string(str_ref(key_info->name), system_charset_info));
00240 uint32_t length= internal::int64_t2str(tab->ref.key_length, keylen_str_buf, 10) - keylen_str_buf;
00241 item_list.push_back(new Item_string(keylen_str_buf, length, system_charset_info));
00242 for (StoredKey **ref= tab->ref.key_copy; *ref; ref++)
00243 {
00244 if (tmp2.length())
00245 tmp2.append(",");
00246 tmp2.append((*ref)->name(),
00247 strlen((*ref)->name()));
00248 }
00249 item_list.push_back(new Item_string(tmp2, cs));
00250 }
00251 else if (tab->type == AM_NEXT)
00252 {
00253 KeyInfo *key_info=table->key_info+ tab->index;
00254 item_list.push_back(new Item_string(str_ref(key_info->name),cs));
00255 uint32_t length= internal::int64_t2str(key_info->key_length, keylen_str_buf, 10) - keylen_str_buf;
00256 item_list.push_back(new Item_string(keylen_str_buf, length, system_charset_info));
00257 item_list.push_back(item_null);
00258 }
00259 else if (tab->select && tab->select->quick)
00260 {
00261 tab->select->quick->add_keys_and_lengths(&tmp2, &tmp3);
00262 item_list.push_back(new Item_string(tmp2, cs));
00263 item_list.push_back(new Item_string(tmp3, cs));
00264 item_list.push_back(item_null);
00265 }
00266 else
00267 {
00268 item_list.push_back(item_null);
00269 item_list.push_back(item_null);
00270 item_list.push_back(item_null);
00271 }
00272
00273
00274 double examined_rows;
00275 if (tab->select && tab->select->quick)
00276 {
00277 examined_rows= tab->select->quick->records;
00278 }
00279 else if (tab->type == AM_NEXT || tab->type == AM_ALL)
00280 {
00281 examined_rows= tab->limit ? tab->limit : tab->table->cursor->records();
00282 }
00283 else
00284 {
00285 optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
00286 examined_rows= cur_pos.getFanout();
00287 }
00288
00289 item_list.push_back(new Item_int((int64_t) (uint64_t) examined_rows,
00290 MY_INT64_NUM_DECIMAL_DIGITS));
00291
00292
00293 if (join->session->lex().describe & DESCRIBE_EXTENDED)
00294 {
00295 float f= 0.0;
00296 if (examined_rows)
00297 {
00298 optimizer::Position cur_pos= join->getPosFromOptimalPlan(i);
00299 f= static_cast<float>(100.0 * cur_pos.getFanout() / examined_rows);
00300 }
00301 item_list.push_back(new Item_float(f, 2));
00302 }
00303
00304
00305 bool key_read= table->key_read;
00306 if ((tab->type == AM_NEXT || tab->type == AM_CONST) &&
00307 table->covering_keys.test(tab->index))
00308 key_read= 1;
00309 if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT &&
00310 ! ((optimizer::QuickRorIntersectSelect *) tab->select->quick)->need_to_fetch_row)
00311 key_read= 1;
00312
00313 if (tab->info)
00314 item_list.push_back(new Item_string(str_ref(tab->info),cs));
00315 else if (tab->packed_info & TAB_INFO_HAVE_VALUE)
00316 {
00317 if (tab->packed_info & TAB_INFO_USING_INDEX)
00318 extra.append("; Using index");
00319 if (tab->packed_info & TAB_INFO_USING_WHERE)
00320 extra.append("; Using where");
00321 if (tab->packed_info & TAB_INFO_FULL_SCAN_ON_NULL)
00322 extra.append("; Full scan on NULL key");
00323 if (extra.length())
00324 extra.erase(0, 2);
00325 item_list.push_back(new Item_string(extra, cs));
00326 }
00327 else
00328 {
00329 if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_UNION ||
00330 quick_type == optimizer::QuickSelectInterface::QS_TYPE_ROR_INTERSECT ||
00331 quick_type == optimizer::QuickSelectInterface::QS_TYPE_INDEX_MERGE)
00332 {
00333 extra.append("; Using ");
00334 tab->select->quick->add_info_string(&extra);
00335 }
00336 if (tab->select)
00337 {
00338 if (tab->use_quick == 2)
00339 {
00340
00341
00342
00343
00344
00345
00346
00347
00348 stringstream s, w;
00349 string str;
00350 w << tab->keys;
00351 w >> str;
00352 for (uint32_t pos= 0; pos < tab->keys.size(); pos+= 32)
00353 {
00354 bitset<32> tmp(str, pos, 32);
00355 if (tmp.any())
00356 s << uppercase << hex << tmp.to_ulong();
00357 }
00358 extra.append("; Range checked for each record (index map: 0x");
00359 extra.append(s.str().c_str());
00360 extra.append(")");
00361 }
00362 else if (tab->select->cond)
00363 {
00364 extra.append("; Using where");
00365 }
00366 }
00367 if (key_read)
00368 {
00369 if (quick_type == optimizer::QuickSelectInterface::QS_TYPE_GROUP_MIN_MAX)
00370 extra.append("; Using index for group-by");
00371 else
00372 extra.append("; Using index");
00373 }
00374 if (table->reginfo.not_exists_optimize)
00375 extra.append("; Not exists");
00376
00377 if (need_tmp_table)
00378 {
00379 need_tmp_table=0;
00380 extra.append("; Using temporary");
00381 }
00382 if (need_order)
00383 {
00384 need_order=0;
00385 extra.append("; Using filesort");
00386 }
00387 if (distinct & test_all_bits(used_tables,session->used_tables))
00388 extra.append("; Distinct");
00389
00390 if (tab->insideout_match_tab)
00391 {
00392 extra.append("; LooseScan");
00393 }
00394
00395 for (uint32_t part= 0; part < tab->ref.key_parts; part++)
00396 {
00397 if (tab->ref.cond_guards[part])
00398 {
00399 extra.append("; Full scan on NULL key");
00400 break;
00401 }
00402 }
00403
00404 if (i > 0 && tab[-1].next_select == sub_select_cache)
00405 extra.append("; Using join buffer");
00406
00407 if (extra.length())
00408 extra.erase(0, 2);
00409 item_list.push_back(new Item_string(extra, cs));
00410 }
00411
00412 used_tables|=table->map;
00413 if (result->send_data(item_list))
00414 join->error= 1;
00415 }
00416 }
00417 for (Select_Lex_Unit *unit= join->select_lex->first_inner_unit();
00418 unit;
00419 unit= unit->next_unit())
00420 {
00421 if (explainUnion(session, unit, result))
00422 return;
00423 }
00424 return;
00425 }
00426
00427 bool optimizer::ExplainPlan::explainUnion(Session *session,
00428 Select_Lex_Unit *unit,
00429 select_result *result)
00430 {
00431 bool res= false;
00432 Select_Lex *first= unit->first_select();
00433
00434 for (Select_Lex *sl= first;
00435 sl;
00436 sl= sl->next_select())
00437 {
00438
00439 sl->uncacheable.reset(UNCACHEABLE_EXPLAIN);
00440 if (&session->lex().select_lex == sl)
00441 {
00442 if (sl->first_inner_unit() || sl->next_select())
00443 {
00444 sl->type= optimizer::ST_PRIMARY;
00445 }
00446 else
00447 {
00448 sl->type= optimizer::ST_SIMPLE;
00449 }
00450 }
00451 else
00452 {
00453 if (sl == first)
00454 {
00455 if (sl->linkage == DERIVED_TABLE_TYPE)
00456 {
00457 sl->type= optimizer::ST_DERIVED;
00458 }
00459 else
00460 {
00461 if (sl->uncacheable.test(UNCACHEABLE_DEPENDENT))
00462 {
00463 sl->type= optimizer::ST_DEPENDENT_SUBQUERY;
00464 }
00465 else
00466 {
00467 if (sl->uncacheable.any())
00468 {
00469 sl->type= optimizer::ST_UNCACHEABLE_SUBQUERY;
00470 }
00471 else
00472 {
00473 sl->type= optimizer::ST_SUBQUERY;
00474 }
00475 }
00476 }
00477 }
00478 else
00479 {
00480 if (sl->uncacheable.test(UNCACHEABLE_DEPENDENT))
00481 {
00482 sl->type= optimizer::ST_DEPENDENT_UNION;
00483 }
00484 else
00485 {
00486 if (sl->uncacheable.any())
00487 {
00488 sl->type= optimizer::ST_UNCACHEABLE_UNION;
00489 }
00490 else
00491 {
00492 sl->type= optimizer::ST_UNION;
00493 }
00494 }
00495 }
00496 }
00497 sl->options|= SELECT_DESCRIBE;
00498 }
00499
00500 if (unit->is_union())
00501 {
00502 unit->fake_select_lex->select_number= UINT_MAX;
00503 unit->fake_select_lex->type= optimizer::ST_UNION_RESULT;
00504 unit->fake_select_lex->options|= SELECT_DESCRIBE;
00505 if (! (res= unit->prepare(session, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
00506 {
00507 res= unit->exec();
00508 }
00509 res|= unit->cleanup();
00510 }
00511 else
00512 {
00513 session->lex().current_select= first;
00514 unit->set_limit(unit->global_parameters);
00515 res= select_query(session,
00516 &first->ref_pointer_array,
00517 (TableList*) first->table_list.first,
00518 first->with_wild,
00519 first->item_list,
00520 first->where,
00521 first->order_list.elements + first->group_list.elements,
00522 (Order*) first->order_list.first,
00523 (Order*) first->group_list.first,
00524 first->having,
00525 first->options | session->options | SELECT_DESCRIBE,
00526 result,
00527 unit,
00528 first);
00529 }
00530 return (res || session->is_error());
00531 }
00532
00533 }