-
-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathQueryPlanAnalyzerPgSql.php
More file actions
81 lines (67 loc) · 2.76 KB
/
Copy pathQueryPlanAnalyzerPgSql.php
File metadata and controls
81 lines (67 loc) · 2.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?php
declare(strict_types=1);
namespace staabm\PHPStanDba\Analyzer;
use PDO;
use PHPStan\ShouldNotHappenException;
use staabm\PHPStanDba\QueryReflection\QueryReflection;
final class QueryPlanAnalyzerPgSql implements Analyzer
{
/** @var PDO */
private $connection;
public function __construct(PDO $connection)
{
$this->connection = $connection;
}
public function analyze(string $query): QueryPlanResult
{
$simulatedQuery = 'EXPLAIN (FORMAT JSON) '.$query;
$stmt = $this->connection->query($simulatedQuery);
return $this->buildResult($simulatedQuery, $stmt);
}
/** @param \PDOStatement<array<float|int|string|null>> $stmt */
private static function buildResult(string $simulatedQuery, $stmt): QueryPlanResult
{
$allowedUnindexedReads = QueryReflection::getRuntimeConfiguration()->getNumberOfAllowedUnindexedReads();
if (false === $allowedUnindexedReads) {
throw new ShouldNotHappenException();
}
$allowedRowsNotRequiringIndex = QueryReflection::getRuntimeConfiguration()->getNumberOfRowsNotRequiringIndex();
if (false === $allowedRowsNotRequiringIndex) {
throw new ShouldNotHappenException();
}
$queryPlanResult = new QueryPlanResult($simulatedQuery);
$result = $stmt->fetch();
$queryPlans = \is_array($result) && \array_key_exists('QUERY PLAN', $result)
? json_decode($result['QUERY PLAN'], true)
: [];
\assert(\is_array($queryPlans));
foreach ($queryPlans as $queryPlan) {
$plan = $queryPlan['Plan'];
$table = $plan['Alias'] ?? null;
if (null === $table) {
continue;
}
$rowReads = $plan['Plan Rows'];
$nodeType = $plan['Node Type'];
if ('Seq Scan' === $nodeType && $rowReads >= $allowedRowsNotRequiringIndex) {
$queryPlanResult->addRow($table, QueryPlanResult::ROW_SEQ_SCAN);
}
if ('Bitmap Heap Scan' === $nodeType) {
$queryPlanResult->addRow($table, QueryPlanResult::ROW_BITMAP_HEAP_SCAN);
}
if ('Bitmap Index Scan' === $nodeType) {
$queryPlanResult->addRow($table, QueryPlanResult::ROW_BITMAP_INDEX_SCAN);
}
if ('Index Scan' === $nodeType) {
$queryPlanResult->addRow($table, QueryPlanResult::ROW_INDEX_SCAN);
}
if ('Aggregate' === $nodeType) {
$queryPlanResult->addRow($table, QueryPlanResult::ROW_AGGREGATE);
}
if ('Hash Aggregate' === $nodeType) {
$queryPlanResult->addRow($table, QueryPlanResult::ROW_HASH_AGGREGATE);
}
}
return $queryPlanResult;
}
}