PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/perfmon/admin/perfmon_index_list.php

https://gitlab.com/alexprowars/bitrix
PHP | 426 lines | 380 code | 41 blank | 5 comment | 51 complexity | 66258acaf450a3ca072909c05f28c752 MD5 | raw file
  1. <?
  2. use Bitrix\Main\Loader;
  3. define("ADMIN_MODULE_NAME", "perfmon");
  4. define("PERFMON_STOP", true);
  5. require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php");
  6. /** @global CMain $APPLICATION */
  7. /** @global CDatabase $DB */
  8. /** @global CUser $USER */
  9. Loader::includeModule('perfmon');
  10. require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/perfmon/prolog.php");
  11. IncludeModuleLangFile(__FILE__);
  12. $RIGHT = $APPLICATION->GetGroupRight("perfmon");
  13. if ($RIGHT == "D" || $DB->type !== "MYSQL")
  14. $APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));
  15. $sTableID = "tbl_perfmon_index_list";
  16. $oSort = new CAdminSorting($sTableID, "TABLE_NAME", "asc");
  17. $lAdmin = new CAdminList($sTableID, $oSort);
  18. $go = false;
  19. if ($lAdmin->GroupAction())
  20. {
  21. switch ($_REQUEST['action'])
  22. {
  23. case "analyze_start":
  24. CPerfomanceIndexSuggest::Clear();
  25. $last_id = 0;
  26. $go = true;
  27. $_SESSION["queries"] = 0;
  28. break;
  29. case "analyze_cont":
  30. $etime = time() + 5;
  31. $last_id = intval($_REQUEST["last_id"]);
  32. $sql_cache = array();
  33. while (time() < $etime)
  34. {
  35. $rsSQL = CPerfomanceSQL::GetList(
  36. array("ID", "SQL_TEXT", "QUERY_TIME"),
  37. array(">ID" => $last_id),
  38. array("ID" => "ASC"),
  39. false,
  40. array("nTopCount" => 100)
  41. );
  42. while ($arSQL = $rsSQL->Fetch())
  43. {
  44. $_SESSION["queries"]++;
  45. $go = true;
  46. $sql_md5 = md5(CPerfQuery::remove_literals($arSQL["SQL_TEXT"]));
  47. //Check if did it already on previous steps
  48. if (!array_key_exists($sql_md5, $sql_cache))
  49. {
  50. $sql_cache[$sql_md5] = true;
  51. $rsInd = CPerfomanceIndexSuggest::GetList(array("SQL_MD5"), array("=SQL_MD5" => $sql_md5), array());
  52. if ($rsInd->Fetch())
  53. {
  54. CPerfomanceIndexSuggest::UpdateStat($sql_md5, 1, $arSQL["QUERY_TIME"], $arSQL["ID"]);
  55. }
  56. else
  57. {
  58. $arMissedKeys = array();
  59. $q = new CPerfQuery;
  60. $strSQL = $q->transform2select($arSQL["SQL_TEXT"]);
  61. if ($strSQL && $q->parse($strSQL))
  62. {
  63. $i = 0;
  64. $arExplain = array();
  65. $rsData = $DB->Query("explain ".$strSQL, true);
  66. if (is_object($rsData))
  67. {
  68. while ($arRes = $rsData->Fetch())
  69. {
  70. $i++;
  71. $arExplain[] = $arRes;
  72. if (
  73. $arRes["type"] === "ALL"
  74. && $arRes["key"] == ''
  75. && is_object($q)
  76. && ($i > 1 || $q->has_where($arRes["table"]))
  77. )
  78. {
  79. $missed_keys = $q->suggest_index($arRes["table"]);
  80. if ($missed_keys)
  81. $arMissedKeys = array_merge($arMissedKeys, $missed_keys);
  82. elseif ($q->has_where())
  83. {
  84. //Check if it is possible to find missed keys on joined tables
  85. foreach ($q->table_joins($arRes["table"]) as $alias => $join_columns)
  86. {
  87. $missed_keys = $q->suggest_index($alias);
  88. if ($missed_keys)
  89. $arMissedKeys = array_merge($arMissedKeys, $missed_keys);
  90. }
  91. }
  92. }
  93. }
  94. }
  95. }
  96. if (!empty($arMissedKeys))
  97. {
  98. foreach (array_unique($arMissedKeys) as $suggest)
  99. {
  100. list($alias, $table, $columns) = explode(":", $suggest);
  101. if (
  102. !CPerfQueryStat::IsBanned($table, $columns)
  103. && !CPerfomanceIndexComplete::IsBanned($table, $columns)
  104. )
  105. {
  106. if (
  107. CPerfQueryStat::GatherExpressStat($table, $columns, $q)
  108. && !CPerfQueryStat::IsSelective($table, $columns, $q)
  109. )
  110. CPerfQueryStat::Ban($table, $columns);
  111. else
  112. {
  113. CPerfomanceIndexSuggest::Add(array(
  114. "TABLE_NAME" => $table,
  115. "TABLE_ALIAS" => $alias,
  116. "COLUMN_NAMES" => $columns,
  117. "SQL_TEXT" => $arSQL["SQL_TEXT"],
  118. "SQL_MD5" => $sql_md5,
  119. "SQL_COUNT" => 0,
  120. "SQL_TIME" => 0,
  121. "SQL_EXPLAIN" => serialize($arExplain),
  122. ));
  123. }
  124. }
  125. }
  126. CPerfomanceIndexSuggest::UpdateStat($sql_md5, 1, $arSQL["QUERY_TIME"], $arSQL["ID"]);
  127. }
  128. }
  129. }
  130. else
  131. {
  132. CPerfomanceIndexSuggest::UpdateStat($sql_md5, 1, $arSQL["QUERY_TIME"], $arSQL["ID"]);
  133. }
  134. $last_id = $arSQL["ID"];
  135. }
  136. }
  137. break;
  138. }
  139. if ($go)
  140. {
  141. $lAdmin->BeginPrologContent();
  142. $message = new CAdminMessage(array(
  143. "MESSAGE" => GetMessage("PERFMON_INDEX_IN_PROGRESS"),
  144. "DETAILS" => GetMessage("PERFMON_INDEX_QUERIES_ANALYZED", array("#QUERIES#" => "<b>".intval($_SESSION["queries"])."</b>"))."<br>",
  145. "HTML" => true,
  146. "TYPE" => "PROGRESS",
  147. ));
  148. echo $message->Show();
  149. ?>
  150. <script>
  151. <?echo $lAdmin->ActionDoGroup(0, "analyze_cont", "last_id=".$last_id);?>
  152. </script>
  153. <?
  154. $lAdmin->EndPrologContent();
  155. }
  156. else
  157. {
  158. $lAdmin->BeginPrologContent();
  159. $message = new CAdminMessage(array(
  160. "MESSAGE" => GetMessage("PERFMON_INDEX_COMPLETE"),
  161. "DETAILS" => GetMessage("PERFMON_INDEX_QUERIES_ANALYZED", array("#QUERIES#" => "<b>".intval($_SESSION["queries"])."</b>"))."<br>",
  162. "HTML" => true,
  163. "TYPE" => "OK",
  164. ));
  165. echo $message->Show();
  166. $lAdmin->EndPrologContent();
  167. }
  168. }
  169. if (!$go && CPerfomanceKeeper::IsActive())
  170. {
  171. $lAdmin->BeginPrologContent();
  172. $message = new CAdminMessage(array(
  173. "MESSAGE" => GetMessage("PERFMON_INDEX_KEEPER_NOTE_IS_ACTIVE"),
  174. "DETAILS" => GetMessage("PERFMON_INDEX_KEEPER_NOTE_ANALYZE")."<br>",
  175. "HTML" => true,
  176. "TYPE" => "OK",
  177. ));
  178. echo $message->Show();
  179. $lAdmin->EndPrologContent();
  180. }
  181. $lAdmin->AddHeaders(array(
  182. array(
  183. "id" => "BANNED",
  184. "content" => GetMessage("PERFMON_INDEX_BANNED"),
  185. "align" => "center",
  186. "default" => true,
  187. ),
  188. array(
  189. "id" => "TABLE_NAME",
  190. "content" => GetMessage("PERFMON_INDEX_TABLE_NAME"),
  191. "default" => true,
  192. "sort" => "TABLE_NAME",
  193. ),
  194. array(
  195. "id" => "COLUMN_NAMES",
  196. "content" => GetMessage("PERFMON_INDEX_COLUMN_NAMES"),
  197. "default" => true,
  198. ),
  199. array(
  200. "id" => "SQL_COUNT",
  201. "content" => GetMessage("PERFMON_INDEX_SQL_COUNT"),
  202. "align" => "right",
  203. "default" => true,
  204. "sort" => "SQL_COUNT",
  205. ),
  206. array(
  207. "id" => "SQL_TIME_AVG",
  208. "content" => GetMessage("PERFMON_INDEX_SQL_TIME_AVG"),
  209. "align" => "right",
  210. "default" => true,
  211. ),
  212. array(
  213. "id" => "SQL_TIME",
  214. "content" => GetMessage("PERFMON_INDEX_SQL_TIME"),
  215. "align" => "right",
  216. "default" => true,
  217. "sort" => "SQL_TIME",
  218. ),
  219. array(
  220. "id" => "SQL_TEXT",
  221. "content" => GetMessage("PERFMON_INDEX_SQL_TEXT"),
  222. "default" => true,
  223. ),
  224. ));
  225. $arSelectedFields = $lAdmin->GetVisibleHeaderColumns();
  226. if (!is_array($arSelectedFields) || (count($arSelectedFields) < 1))
  227. $arSelectedFields = array(
  228. "TABLE_NAME",
  229. "COLUMN_NAMES",
  230. "SQL_COUNT",
  231. "SQL_TIME",
  232. "SQL_TEXT",
  233. );
  234. $arSelectedFields[] = "ID";
  235. $cData = new CPerfomanceIndexSuggest;
  236. $rsData = $cData->GetList($arSelectedFields, array("!=BANNED" => "Y"), array($by => $order));
  237. $rsData = new CAdminResult($rsData, $sTableID);
  238. $rsData->NavStart();
  239. $lAdmin->NavText($rsData->GetNavPrint(GetMessage("PERFMON_INDEX_PAGE")));
  240. while ($arRes = $rsData->NavNext(true, "f_"))
  241. {
  242. $arRes["SQL_TEXT"] = CPerfomanceSQL::Format($arRes["SQL_TEXT"]);
  243. $row =& $lAdmin->AddRow($f_NAME, $arRes);
  244. $row->AddViewField("SQL_TIME", perfmon_NumberFormat($f_SQL_TIME, 6));
  245. if ($f_SQL_COUNT > 0)
  246. {
  247. $row->AddViewField("SQL_TIME_AVG", perfmon_NumberFormat($f_SQL_TIME / $f_SQL_COUNT, 6));
  248. }
  249. $row->AddViewField("SQL_COUNT", '<a href="perfmon_sql_list.php?lang='.LANGUAGE_ID.'&amp;set_filter=Y&amp;find_suggest_id='.$f_ID.'">'.$f_SQL_COUNT.'</a>');
  250. $row->AddViewField("COLUMN_NAMES", str_replace(",", "<br>", $f_COLUMN_NAMES));
  251. if ($f_BANNED == "N")
  252. $row->AddViewField("BANNED", '<span class="adm-lamp adm-lamp-in-list adm-lamp-green" title="'.htmlspecialcharsbx(GetMessage("PERFMON_INDEX_GREEN_ALT")).'"></span>');
  253. elseif ($f_BANNED == "Y")
  254. $row->AddViewField("BANNED", '<span class="adm-lamp adm-lamp-in-list adm-lamp-red" title="'.htmlspecialcharsbx(GetMessage("PERFMON_INDEX_RED_ALT")).'"></span>');
  255. else
  256. $row->AddViewField("BANNED", '<span class="adm-lamp adm-lamp-in-list adm-lamp-yellow" title="'.htmlspecialcharsbx(GetMessage("PERFMON_INDEX_YELLOW_ALT")).'"></span>');
  257. $rsQueries = CPerfomanceSQL::GetList(
  258. array("ID"),
  259. array("=SUGGEST_ID" => $f_ID),
  260. array("ID" => "ASC"),
  261. false,
  262. array("nTopCount" => 1)
  263. );
  264. if ($arQuery = $rsQueries->GetNext())
  265. $f_SQL_ID = $arQuery["ID"];
  266. else
  267. $f_SQL_ID = "";
  268. if (class_exists("geshi") && $f_SQL_TEXT)
  269. {
  270. $obGeSHi = new GeSHi($arRes["SQL_TEXT"], 'sql');
  271. $html = $obGeSHi->parse_code();
  272. }
  273. else
  274. {
  275. $html = str_replace(
  276. array(" ", "\n"),
  277. array(" &nbsp;", "<br>"),
  278. htmlspecialcharsbx($arRes["SQL_TEXT"])
  279. );
  280. }
  281. $html = '<span onmouseover="addTimer(this)" onmouseout="removeTimer(this)" id="'.$f_SQL_ID.'_sql_backtrace">'.$html.'</span>';
  282. $row->AddViewField("SQL_TEXT", $html);
  283. $arActions = array(
  284. array(
  285. "DEFAULT" => "Y",
  286. "TEXT" => GetMessage("PERFMON_INDEX_DETAILS"),
  287. "ACTION" => $lAdmin->ActionRedirect('perfmon_index_detail.php?lang='.LANG.'&ID='.$f_ID),
  288. ),
  289. );
  290. if ($f_SQL_ID)
  291. {
  292. $arActions[] = array(
  293. "TEXT" => GetMessage("PERFMON_INDEX_EXPLAIN"),
  294. "ACTION" => 'jsUtils.OpenWindow(\'perfmon_explain.php?lang='.LANG.'&ID='.$arQuery["ID"].'\', 600, 500);',
  295. );
  296. }
  297. $row->AddActions($arActions);
  298. }
  299. $lAdmin->AddFooter(
  300. array(
  301. array(
  302. "title" => GetMessage("MAIN_ADMIN_LIST_SELECTED"),
  303. "value" => $rsData->SelectedRowsCount(),
  304. ),
  305. )
  306. );
  307. $aContext = array();
  308. if ($go || !CPerfomanceKeeper::IsActive())
  309. {
  310. $aContext[] = array(
  311. "TEXT" => GetMessage("PERFMON_INDEX_ANALYZE"),
  312. "LINK" => "javascript:".$lAdmin->ActionDoGroup(0, "analyze_start"),
  313. );
  314. }
  315. $lAdmin->AddAdminContextMenu($aContext);
  316. $lAdmin->CheckListMode();
  317. $APPLICATION->SetTitle(GetMessage("PERFMON_INDEX_TITLE"));
  318. require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");
  319. CJSCore::Init(array("ajax", "popup"));
  320. ?>
  321. <script>
  322. var toolTipCache = new Array;
  323. function drawTooltip(result, _this)
  324. {
  325. if (!_this)
  326. _this = this;
  327. if (result != 'no backtrace found')
  328. {
  329. _this.toolTip = BX.PopupWindowManager.create(
  330. 'table_tooltip_' + (parseInt(Math.random() * 100000)), _this,
  331. {
  332. autoHide: true,
  333. closeIcon: true,
  334. closeByEsc: true,
  335. content: result
  336. }
  337. );
  338. _this.toolTip.show();
  339. }
  340. _this.toolTip.show();
  341. toolTipCache[_this.id] = result;
  342. }
  343. function sendRequest()
  344. {
  345. if (this.toolTip)
  346. this.toolTip.show();
  347. else if (toolTipCache[this.id])
  348. drawTooltip(toolTipCache[this.id], this);
  349. else
  350. BX.ajax.get(
  351. 'perfmon_sql_list.php?ajax_tooltip=y' + '&sessid=' + BX.message('bitrix_sessid') + '&sql_id=' + this.id,
  352. BX.proxy(drawTooltip, this)
  353. );
  354. }
  355. function addTimer(p_href)
  356. {
  357. p_href.timerID = setTimeout(BX.proxy(sendRequest, p_href), 1000);
  358. }
  359. function removeTimer(p_href)
  360. {
  361. if (p_href.timerID)
  362. {
  363. clearTimeout(p_href.timerID);
  364. p_href.timerID = null;
  365. }
  366. }
  367. function Analyze()
  368. {
  369. var url = 'perfmon_index_list.php?lang=<?echo LANGUAGE_ID?>&<?echo bitrix_sessid_get()?>&action=analyze';
  370. ShowWaitWindow();
  371. BX.ajax.post(
  372. url,
  373. null,
  374. function (result)
  375. {
  376. CloseWaitWindow();
  377. if (result.length > 0 && result.indexOf("MoveProgress") < 0)
  378. document.getElementById('progress_message').innerHTML = result;
  379. }
  380. );
  381. }
  382. </script>
  383. <?
  384. $lAdmin->DisplayList();
  385. require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_admin.php");?>