/** * @phutil-external-symbol class PhabricatorStartup */ public function generateData() { $should_analyze = self::isQueryAnalyzerRequested(); $log = PhutilServiceProfiler::getInstance()->getServiceCallLog(); foreach ($log as $key => $entry) { $config = idx($entry, 'config', array()); unset($log[$key]['config']); if (!$should_analyze) { $log[$key]['explain'] = array('sev' => 7, 'size' => null, 'reason' => pht('Disabled')); // Query analysis is disabled for this request, so don't do any of it. continue; } if ($entry['type'] != 'query') { continue; } // For each SELECT query, go issue an EXPLAIN on it so we can flag stuff // causing table scans, etc. if (preg_match('/^\\s*SELECT\\b/i', $entry['query'])) { $conn = PhabricatorEnv::newObjectFromConfig('mysql.implementation', array($entry['config'])); try { $explain = queryfx_all($conn, 'EXPLAIN %Q', $entry['query']); $badness = 0; $size = 1; $reason = null; foreach ($explain as $table) { $size *= (int) $table['rows']; switch ($table['type']) { case 'index': $cur_badness = 1; $cur_reason = 'Index'; break; case 'const': $cur_badness = 1; $cur_reason = 'Const'; break; case 'eq_ref': $cur_badness = 2; $cur_reason = 'EqRef'; break; case 'range': $cur_badness = 3; $cur_reason = 'Range'; break; case 'ref': $cur_badness = 3; $cur_reason = 'Ref'; break; case 'fulltext': $cur_badness = 3; $cur_reason = 'Fulltext'; break; case 'ALL': if (preg_match('/Using where/', $table['Extra'])) { if ($table['rows'] < 256 && !empty($table['possible_keys'])) { $cur_badness = 2; $cur_reason = pht('Small Table Scan'); } else { $cur_badness = 6; $cur_reason = pht('TABLE SCAN!'); } } else { $cur_badness = 3; $cur_reason = pht('Whole Table'); } break; default: if (preg_match('/No tables used/i', $table['Extra'])) { $cur_badness = 1; $cur_reason = pht('No Tables'); } else { if (preg_match('/Impossible/i', $table['Extra'])) { $cur_badness = 1; $cur_reason = pht('Empty'); } else { $cur_badness = 4; $cur_reason = pht("Can't Analyze"); } } break; } if ($cur_badness > $badness) { $badness = $cur_badness; $reason = $cur_reason; } } $log[$key]['explain'] = array('sev' => $badness, 'size' => $size, 'reason' => $reason); } catch (Exception $ex) { $log[$key]['explain'] = array('sev' => 5, 'size' => null, 'reason' => $ex->getMessage()); } } } return array('start' => PhabricatorStartup::getStartTime(), 'end' => microtime(true), 'log' => $log, 'analyzeURI' => (string) $this->getRequestURI()->alter('__analyze__', true), 'didAnalyze' => $should_analyze); }