| Current Path : /var/www/homesaver/www/bitrix/modules/perfmon/admin/ |
| Current File : /var/www/homesaver/www/bitrix/modules/perfmon/admin/perfmon_index_detail.php |
<?php
use Bitrix\Main\Loader;
define('ADMIN_MODULE_NAME', 'perfmon');
require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_admin_before.php';
/** @var CMain $APPLICATION */
/** @var CDatabase $DB */
/** @var CUser $USER */
$RIGHT = CMain::GetGroupRight('perfmon');
if ($RIGHT == 'D')
{
$APPLICATION->AuthForm(GetMessage('ACCESS_DENIED'));
}
$isAdmin = $USER->CanDoOperation('edit_php');
if (!Loader::includeModule('perfmon'))
{
$APPLICATION->AuthForm(GetMessage('ACCESS_DENIED'));
}
require_once $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/perfmon/prolog.php';
IncludeModuleLangFile(__FILE__);
$aTabs = [
[
'DIV' => 'edit1',
'TAB' => GetMessage('PERFMON_IDETAIL_TABLE_TAB'),
'ICON' => 'main_user_edit',
'TITLE' => GetMessage('PERFMON_IDETAIL_TABLE_TAB_TITLE'),
],
[
'DIV' => 'edit2',
'TAB' => GetMessage('PERFMON_IDETAIL_QUERY_TAB'),
'ICON' => 'main_user_edit',
'TITLE' => GetMessage('PERFMON_IDETAIL_QUERY_TAB_TITLE'),
],
[
'DIV' => 'edit3',
'TAB' => GetMessage('PERFMON_IDETAIL_INDEX_TAB'),
'ICON' => 'main_user_edit',
'TITLE' => GetMessage('PERFMON_IDETAIL_INDEX_TAB_TITLE'),
],
];
$tabControl = new CAdminTabControl('tabControl', $aTabs);
$ID = intval($_REQUEST['ID']); // Id of the edited record
$rsSuggest = CPerfomanceIndexSuggest::GetList(
['ID', 'TABLE_NAME', 'TABLE_ALIAS', 'COLUMN_NAMES', 'SQL_TEXT', 'SQL_EXPLAIN', 'SQL_TIME', 'SQL_COUNT'],
['=ID' => $ID],
[]
);
$arSuggest = $rsSuggest->Fetch();
if (!$arSuggest)
{
$APPLICATION->AuthForm(GetMessage('ACCESS_DENIED'));
}
$sql = CPerfomanceSQL::Format($arSuggest['SQL_TEXT']);
$sql = htmlspecialcharsEx($sql);
$sql = preg_replace('/(' . preg_quote($arSuggest['TABLE_NAME']) . '\\s+(?i:as\\s+)*' . $arSuggest['TABLE_ALIAS'] . ')\\s+/', "<b>\\1</b> ", $sql);
foreach (explode(',', $arSuggest['COLUMN_NAMES']) as $column_name)
{
$sql = str_replace($arSuggest['TABLE_ALIAS'] . '.' . $column_name, '<b>' . $arSuggest['TABLE_ALIAS'] . '.' . $column_name . '</b>', $sql);
}
$arSuggest['FORMATTED_SQL_TEXT'] = $sql;
$arColumns = explode(',', $arSuggest['COLUMN_NAMES']);
$arTableStat = CPerfQueryStat::GatherTableStat($arSuggest['TABLE_NAME']);
$obTable = new CPerfomanceTable;
$obTable->Init($arSuggest['TABLE_NAME']);
$arIndexes = $obTable->GetIndexes();
$arQueries = [];
$rsQueries = CPerfomanceSQL::GetList(
['ID', 'SQL_TEXT'],
['=SUGGEST_ID' => $ID],
['ID' => 'ASC'],
false,
['nTopCount' => 10]
);
while ($arQuery = $rsQueries->Fetch())
{
$arQuery['STAT'] = [];
$arQuery['WHERE'] = [];
$arQuery['JOIN'] = [];
$q = new CPerfQuery;
$select = CPerfQuery::transform2select($arQuery['SQL_TEXT']);
if ($q->parse($select))
{
foreach ($arColumns as $column_name)
{
$arQuery['WHERE'][$column_name] = $q->find_value($arSuggest['TABLE_NAME'], $column_name);
if ($arQuery['WHERE'][$column_name] == '')
{
$arQuery['JOIN'][$column_name] = $q->find_join($arSuggest['TABLE_NAME'], $column_name);
}
else
{
$arQuery['JOIN'][$column_name] = '';
}
}
}
$sql = CPerfomanceSQL::Format($arQuery['SQL_TEXT']);
$sql = htmlspecialcharsEx($sql);
$sql = preg_replace('/(' . preg_quote($arSuggest['TABLE_NAME']) . '\\s+(?i:as\\s+)*' . $arSuggest['TABLE_ALIAS'] . ')\\s+/', "<b>\\1</b> ", $sql);
foreach (explode(',', $arSuggest['COLUMN_NAMES']) as $column_name)
{
$sql = str_replace($arSuggest['TABLE_ALIAS'] . '.' . $column_name, '<b>' . $arSuggest['TABLE_ALIAS'] . '.' . $column_name . '</b>', $sql);
}
$arQuery['FORMATTED_SQL_TEXT'] = $sql;
foreach ($arColumns as $column_name)
{
if ($arQuery['WHERE'][$column_name])
{
$arColStat = CPerfQueryStat::GatherColumnStatByValue($arSuggest['TABLE_NAME'], $column_name, trim($arQuery['WHERE'][$column_name], "'"));
if ($arColStat && $arColStat['TABLE_ROWS'] > 0)
{
$arQuery['STAT'][$column_name] = $arColStat['COLUMN_ROWS'] / $arColStat['TABLE_ROWS'];
}
}
elseif ($arQuery['JOIN'][$column_name])
{
$arColStat = CPerfQueryStat::GatherColumnStatOverall($arSuggest['TABLE_NAME'], $column_name);
if ($arColStat && $arColStat['TABLE_ROWS'] > 0)
{
$arQuery['STAT'][$column_name] = 1 / $arColStat['TABLE_ROWS'];
}
}
else
{
$arQuery['STAT'] = [];
}
}
$arQueries[] = $arQuery;
}
function _sort_index_columns($a, $b)
{
if ($a > $b)
{
return 1;
}
elseif ($a < $b)
{
return -1;
}
else
{
return 0;
}
}
$arIndexColumns = [];
foreach ($arColumns as $column_name)
{
$arIndexColumns[$column_name] = 0;
$i = 0;
foreach ($arQueries as $i => $arQuery)
{
$arIndexColumns[$column_name] += $arQuery['STAT'][$column_name];
}
$arIndexColumns[$column_name] /= $i + 1;
}
if (count($arIndexColumns) > 1)
{
$bHasSelective = false;
foreach ($arIndexColumns as $stat)
{
if ($stat < 0.05)
{
$bHasSelective = true;
}
}
if ($bHasSelective)
{
foreach ($arIndexColumns as $column_name => $stat)
{
if ($stat > 0.05)
{
unset($arIndexColumns[$column_name]);
}
}
}
uasort($arIndexColumns, '_sort_index_columns');
}
$arIndexColumns = array_keys($arIndexColumns);
$table = trim($arSuggest['TABLE_NAME'], '`');
$index = [];
foreach ($arIndexColumns as $indColumn)
{
$index[] = trim($indColumn, '`');
}
$IndexExists = $DB->GetIndexName($table, $index);
$strError = '';
/** @var \Bitrix\Main\HttpRequest $request */
$request = \Bitrix\Main\Context::getCurrent()->getRequest();
if (
$request->isPost()
&& check_bitrix_sessid()
&& $isAdmin
)
{
if (
$request->get('create_index') !== null
&& $request->get('ddl') !== null
)
{
$res = $DB->Query((string)$request->get('ddl'), true);
if (is_object($res))
{
CPerfomanceIndexComplete::Add([
'TABLE_NAME' => $arSuggest['TABLE_NAME'],
'COLUMN_NAMES' => $arSuggest['COLUMN_NAMES'],
'INDEX_NAME' => $_REQUEST['index_name'],
'BANNED' => 'N',
]);
LocalRedirect('/bitrix/admin/perfmon_index_detail.php?ID=' . $ID . '&lang=' . LANGUAGE_ID . '&' . $tabControl->ActiveTabParam());
}
else
{
$strError = $DB->GetErrorMessage();
}
}
elseif (
$request->get('drop_index') !== null
&& $request->get('ddl') !== null
)
{
$res = $DB->Query((string)$request->get('ddl'), true);
if (is_object($res))
{
CPerfomanceIndexComplete::DeleteByTableName($arSuggest['TABLE_NAME'], $arSuggest['COLUMN_NAMES']);
LocalRedirect('/bitrix/admin/perfmon_index_detail.php?ID=' . $ID . '&lang=' . LANGUAGE_ID . '&' . $tabControl->ActiveTabParam());
}
else
{
$strError = $DB->GetErrorMessage();
}
}
elseif ($request->get('ban_index') !== null)
{
CPerfomanceIndexComplete::Add([
'TABLE_NAME' => $arSuggest['TABLE_NAME'],
'COLUMN_NAMES' => $arSuggest['COLUMN_NAMES'],
'INDEX_NAME' => false,
'BANNED' => 'Y',
]);
LocalRedirect('/bitrix/admin/perfmon_index_list.php?lang=' . LANGUAGE_ID);
}
}
$APPLICATION->SetTitle(GetMessage('PERFMON_IDETAIL_TABLE_TITLE'));
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_admin_after.php';
$aMenu = [
[
'TEXT' => GetMessage('PERFMON_IDETAIL_MENU_LIST'),
'TITLE' => GetMessage('PERFMON_IDETAIL_MENU_LIST_TITLE'),
'LINK' => 'perfmon_index_list.php?lang=' . LANGUAGE_ID,
'ICON' => 'btn_list',
]
];
$context = new CAdminContextMenu($aMenu);
$context->Show();
$message = null;
if ($strError)
{
$message = new CAdminMessage([
'MESSAGE' => GetMessage('admin_lib_error'),
'DETAILS' => $strError,
'TYPE' => 'ERROR',
]);
echo $message->Show();
}
?>
<form method="POST" action="<?php echo $APPLICATION->GetCurPage()?>" enctype="multipart/form-data" name="editform" id="editform">
<?php
$tabControl->Begin();
$tabControl->BeginNextTab();
?>
<tr>
<td colspan="2">
<?php echo BeginNote(), GetMessage('PERFMON_IDETAIL_TABLE_NOTE'), EndNote(), '<br>';?>
</td>
</tr>
<tr class="heading">
<td colspan="2"><?php echo GetMessage('PERFMON_IDETAIL_QUERY')?></td>
</tr>
<tr>
<td colspan="2"><?php echo str_replace(
[' ', "\n"],
[' ', '<br>'],
$arSuggest['FORMATTED_SQL_TEXT']
);?></td>
</tr>
<tr class="heading">
<td colspan="2"><?php echo GetMessage('PERFMON_IDETAIL_TABLE_STAT')?></td>
</tr>
<tr>
<td width="40%"><?php echo GetMessage('PERFMON_IDETAIL_TABLE_NAME')?>:</td>
<td width="60%"><?php echo htmlspecialcharsEx($arSuggest['TABLE_NAME']);?></td>
</tr>
<tr>
<td><?php echo GetMessage('PERFMON_IDETAIL_TABLE_SIZE')?>:</td>
<td><?php echo htmlspecialcharsEx(CFile::FormatSize($arTableStat['TABLE_SIZE']));?></td>
</tr>
<tr>
<td><?php echo GetMessage('PERFMON_IDETAIL_TABLE_ROWS')?>:</td>
<td><?php echo htmlspecialcharsEx($arTableStat['TABLE_ROWS']);?></td>
</tr>
<tr class="heading">
<td colspan="2"><?php echo GetMessage('PERFMON_IDETAIL_TABLE_STRUCT')?></td>
</tr>
<tr>
<td align="right" class="adm-detail-valign-top">
<table class="internal">
<tr class="heading">
<td><?php echo GetMessage('PERFMON_IDETAIL_TABLE_COLUMN')?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_COLUMN_DATA_TYPE')?></td>
</tr>
<?php
foreach (CPerfQueryStat::GetTableColumns($arSuggest['TABLE_NAME']) as $column_name => $arColumn):
$b = in_array($column_name, $arColumns);
?>
<tr>
<td><?php echo ($b ? '<b>' : '') . htmlspecialcharsEx($column_name) . ($b ? '</b>' : '')?></td>
<td><?php echo htmlspecialcharsEx($arColumn['Type'])?></td>
</tr>
<?php endforeach?>
</table>
</td>
<td align="left" class="adm-detail-valign-top">
<table class="internal" style="width:100%">
<tr class="heading">
<td><?php echo GetMessage('PERFMON_IDETAIL_INDEX_NAME')?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_INDEX_COLUMNS')?></td>
</tr>
<?php
foreach ($arIndexes as $index_name => $arIndexColumnsTmp):
$arIndexColumnsTmp2 = $arIndexColumnsTmp;
foreach ($arIndexColumnsTmp2 as $i => $index_column)
{
if (in_array($index_column, $arColumns, true))
{
$arIndexColumnsTmp2[$i] = '<b>' . $arIndexColumnsTmp2[$i] . '</b>';
}
}
?>
<tr valign="top">
<td><?php echo htmlspecialcharsbx($index_name)?></td>
<td><?php echo implode('<br>', $arIndexColumnsTmp2)?></td>
</tr>
<?php endforeach?>
</table>
</td>
</tr>
<?php
$tabControl->BeginNextTab();
?>
<tr>
<td>
<?php echo BeginNote(), GetMessage('PERFMON_IDETAIL_QUERY_TAB_NOTE'), EndNote(), '<br>';?>
<table class="internal" style="width:100%">
<tr class="heading">
<td><?php echo GetMessage('PERFMON_IDETAIL_QUERY')?></td>
<?php foreach (explode(',', $arSuggest['COLUMN_NAMES']) as $column_name):?>
<td><?php echo htmlspecialcharsEx($column_name)?></td>
<?php endforeach?>
</tr>
<?php foreach ($arQueries as $arQuery):?>
<tr>
<td align="left"><?php
echo str_replace(
[' ', "\n"],
[' ', '<br>'],
$arQuery['FORMATTED_SQL_TEXT']
);
?></td>
<?php foreach ($arQuery['STAT'] as $column_name => $ratio):?>
<td style="text-align:center"><?php
if (isset($arQuery['WHERE'][$column_name]))
{
echo htmlspecialcharsEx($arQuery['WHERE'][$column_name]);
}
else
{
echo htmlspecialcharsEx($arQuery['JOIN'][$column_name]);
}
$proc = max($ratio * 100, 0.0001);
if ($proc > 5)
{
echo '<br><span class="errortext">',round($proc, 4),'%</span><br>' . GetMessage('PERFMON_IDETAIL_QUERY_IS_BAD');
}
else
{
echo '<br><span class="notetext">',round($proc, 4),'%</span><br>' . GetMessage('PERFMON_IDETAIL_QUERY_IS_GOOD');
}
?></td>
<?php endforeach?>
</tr>
<?php endforeach?>
</table>
</td>
</tr>
<?php
$tabControl->BeginNextTab();
?>
<tr>
<td colspan="2" align="center">
<?php echo BeginNote(), GetMessage('PERFMON_IDETAIL_INDEX_NOTE'), EndNote(), '<br>';?>
</td>
</tr>
<tr class="heading">
<td colspan="2"><?php echo GetMessage('PERFMON_IDETAIL_QUERY')?></td>
</tr>
<tr>
<td colspan="2"><?php echo str_replace(
[' ', "\n"],
[' ', '<br>'],
$arSuggest['FORMATTED_SQL_TEXT']
);?></td>
</tr>
<tr class="heading">
<td colspan="2"><?php echo GetMessage('PERFMON_IDETAIL_EXPLAIN_BEFORE')?></td>
</tr>
<tr>
<td colspan="2" align="center">
<table class="internal">
<tr class="heading">
<td><?php echo GetMessage('PERFMON_IDETAIL_F_SELECT_TYPE');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_TABLE');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_TYPE');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_POSSIBLE_KEYS');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_KEY');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_KEY_LEN');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_REF');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_ROWS');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_EXTRA');?></td>
</tr>
<?php foreach (unserialize($arSuggest['SQL_EXPLAIN'], ['allowed_classes' => false]) as $arRes):?>
<tr>
<td><?php echo htmlspecialcharsEx($arRes['select_type']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['table']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['type']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['possible_keys']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['key']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['key_len']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['ref']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['rows']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['Extra']);?></td>
</tr>
<?php endforeach?>
</table>
</td>
</tr>
<tr>
<td width="50%"><?php echo GetMessage('PERFMON_IDETAIL_AVG_QUERY_TIME')?>:</td>
<td width="50%"><?php echo perfmon_NumberFormat($arSuggest['SQL_TIME'] / $arSuggest['SQL_COUNT'], 6)?></td>
</tr>
<tr class="heading">
<td colspan="2"><?php echo GetMessage('PERFMON_IDETAIL_INDEX')?></td>
</tr>
<?php if ($IndexExists == ''):?>
<tr>
<td><?php echo GetMessage('PERFMON_IDETAIL_CREATE_INDEX_DDL')?>:</td>
<?php
$prefix = mb_substr('ix_perf_' . trim($arSuggest['TABLE_NAME'], '`'), 0, 27) . '_';
$i = 1;
while (array_key_exists($prefix . $i, $arIndexes))
{
$i++;
}
$ddl = $obTable->getCreateIndexDDL($arSuggest['TABLE_NAME'], $prefix . $i, $arIndexColumns);
?>
<td>
<?php echo htmlspecialcharsEx($ddl)?>
<input type="hidden" name="ddl" value="<?php echo htmlspecialcharsbx($ddl)?>">
<input type="hidden" name="index_name" value="<?php echo htmlspecialcharsbx($prefix . $i)?>">
<input type="hidden" name="ID" value="<?php echo $ID?>">
</td>
</tr>
<?php if ($isAdmin)
{
?>
<tr>
<td> </td>
<td valign="middle">
<input type="submit" value="<?php echo GetMessage('PERFMON_IDETAIL_CREATE_INDEX')?>" name="create_index" class="adm-btn-green">
<span style="line-height:27px"><?php echo GetMessage('PERFMON_IDETAIL_OR')?></span>
<input type="submit" value="<?php echo GetMessage('PERFMON_IDETAIL_BAN_INDEX')?>" name="ban_index">
</td>
</tr>
<?php }
?>
<?php else:?>
<tr>
<td><?php echo GetMessage('PERFMON_IDETAIL_CREATED_INDEX_DDL')?>:</td>
<td><?php echo $obTable->getCreateIndexDDL($arSuggest['TABLE_NAME'], $IndexExists, $arIndexes[$IndexExists])?></td>
</tr>
<tr>
<td><?php echo GetMessage('PERFMON_IDETAIL_DROP_INDEX_DDL')?>:</td>
<?php
$ddl = 'ALTER TABLE ' . $arSuggest['TABLE_NAME'] . ' DROP INDEX ' . $IndexExists;
?>
<td>
<?php echo htmlspecialcharsEx($ddl)?>
<input type="hidden" name="ddl" value="<?php echo htmlspecialcharsbx($ddl)?>">
<input type="hidden" name="ID" value="<?php echo $ID?>">
</td>
</tr>
<?php if ($isAdmin)
{
?>
<tr>
<td> </td>
<td>
<input type="submit" value="<?php echo GetMessage('PERFMON_IDETAIL_DROP_INDEX')?>" name="drop_index">
</td>
</tr>
<?php }
?>
<tr class="heading">
<td colspan="2"><?php echo GetMessage('PERFMON_IDETAIL_EXPLAIN_AFTER')?></td>
</tr>
<tr>
<td colspan="2" align="center">
<table class="internal">
<tr class="heading">
<td><?php echo GetMessage('PERFMON_IDETAIL_F_SELECT_TYPE');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_TABLE');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_TYPE');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_POSSIBLE_KEYS');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_KEY');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_KEY_LEN');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_REF');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_ROWS');?></td>
<td><?php echo GetMessage('PERFMON_IDETAIL_F_EXTRA');?></td>
</tr>
<?php
$rsExplain = $DB->Query('explain ' . CPerfQuery::transform2select($arSuggest['SQL_TEXT']));
while ($arRes = $rsExplain->Fetch()):
?>
<tr>
<td><?php echo htmlspecialcharsEx($arRes['select_type']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['table']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['type']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['possible_keys']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['key']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['key_len']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['ref']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['rows']);?></td>
<td><?php echo htmlspecialcharsEx($arRes['Extra']);?></td>
</tr>
<?php endwhile?>
</table>
</td>
</tr>
<?php
$sql = CPerfQuery::transform2select($arSuggest['SQL_TEXT']);
$sql = preg_replace('/^\\s*select\\s+/is', 'SELECT /*SQL_NO_CACHE*/ ', $sql);
$stime = microtime(1);
$rs = $DB->Query($sql);
while ($rs->Fetch());
$etime = microtime(1);
$ratio = ($arSuggest['SQL_TIME'] / $arSuggest['SQL_COUNT']) / ($etime - $stime);
?>
<tr>
<td><?php echo GetMessage('PERFMON_IDETAIL_QUERY_TIME')?>:</td>
<td><?php echo perfmon_NumberFormat($etime - $stime, 6)?></td>
</tr>
<?php
if ($ratio > 1)
{
?>
<tr>
<td><?php echo GetMessage('PERFMON_IDETAIL_GAIN')?>:</td>
<td><span class="notetext"><?php echo perfmon_NumberFormat($ratio * 100, 2), '%'?></span></td>
</tr>
<?php }
?>
<?php endif;?>
<?php echo bitrix_sessid_post();?>
<input type="hidden" name="lang" value="<?php echo LANGUAGE_ID?>">
<input type="hidden" name="ID" value="<?php echo $ID?>">
<?php
$tabControl->End();
?>
</form>
<?php
$tabControl->ShowWarnings('editform', $message);
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_admin.php';