1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Socialblue\LaravelQueryAdviser\Helper; |
4
|
|
|
|
5
|
|
|
use Illuminate\Database\Eloquent\Builder; |
6
|
|
|
use Illuminate\Support\Facades\DB; |
7
|
|
|
|
8
|
|
|
class QueryBuilderHelper |
9
|
|
|
{ |
10
|
|
|
public static function infoByBuilder($builder) |
11
|
|
|
{ |
12
|
|
|
return [ |
13
|
|
|
'toSql' => $builder->toSql(), |
14
|
|
|
'bindings' => $builder->getBindings(), |
15
|
|
|
'query' => self::addBindingsToQuery($builder), |
|
|
|
|
16
|
|
|
'optimizeQuery' => self::showOptimizedQuery($builder) |
|
|
|
|
17
|
|
|
]; |
18
|
|
|
} |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @param $builder |
22
|
|
|
* @return mixed |
23
|
|
|
*/ |
24
|
|
|
public static function getQueryByBuilder($builder) |
25
|
|
|
{ |
26
|
|
|
return self::addBindingsToQuery($builder); |
|
|
|
|
27
|
|
|
} |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @param $sql |
31
|
|
|
* @param $bindings |
32
|
|
|
* @return string|string[]|null |
33
|
|
|
*/ |
34
|
|
|
public static function combineQueryAndBindings($sql, $bindings) |
35
|
|
|
{ |
36
|
|
|
$pdo = DB::connection()->getPdo(); |
37
|
|
|
|
38
|
|
|
while (strpos($sql, '?') !== false) { |
39
|
|
|
$value = array_shift($bindings); |
40
|
|
|
$sql = preg_replace('/\?/', $pdo->quote(addslashes(addslashes($value))), $sql, 1); |
41
|
|
|
} |
42
|
|
|
return $sql; |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @return array |
47
|
|
|
*/ |
48
|
|
|
public static function getServerInfo(): array |
49
|
|
|
{ |
50
|
|
|
return [ |
51
|
|
|
'info' => |
52
|
|
|
DB::connection() |
53
|
|
|
->getPdo() |
54
|
|
|
->getAttribute(\PDO::ATTR_SERVER_INFO), |
55
|
|
|
'version' => |
56
|
|
|
DB::connection() |
57
|
|
|
->getPdo() |
58
|
|
|
->getAttribute(\PDO::ATTR_SERVER_VERSION), |
59
|
|
|
'client' => |
60
|
|
|
DB::connection() |
61
|
|
|
->getPdo() |
62
|
|
|
->getAttribute(\PDO::ATTR_CLIENT_VERSION), |
63
|
|
|
'status' => |
64
|
|
|
DB::connection() |
65
|
|
|
->getPdo() |
66
|
|
|
->getAttribute(\PDO::ATTR_CONNECTION_STATUS), |
67
|
|
|
]; |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* |
72
|
|
|
* |
73
|
|
|
id – a sequential identifier for each SELECT within the query (for when you have nested subqueries) |
74
|
|
|
select_type – the type of SELECT query. Possible values are: |
75
|
|
|
table – the table referred to by the row |
76
|
|
|
type – how MySQL joins the tables used. This is one of the most insightful fields in the output because it can indicate missing indexes or how the query is written should be reconsidered. Possible values are: |
77
|
|
|
possible_keys – shows the keys that can be used by MySQL to find rows from the table, though they may or may not be used in practice. In fact, this column can often help in optimizing queries since if the column is NULL, it indicates no relevant indexes could be found. |
78
|
|
|
key – indicates the actual index used by MySQL. This column may contain an index that is not listed in the possible_key column. MySQL optimizer always look for an optimal key that can be used for the query. While joining many tables, it may figure out some other keys which is not listed in possible_key but are more optimal. |
79
|
|
|
key_len – indicates the length of the index the Query Optimizer chose to use. For example, a key_len value of 4 means it requires memory to store four characters. Check out MySQL’s data type storage requirements to know more about this. |
80
|
|
|
ref – Shows the columns or constants that are compared to the index named in the key column. MySQL will either pick a constant value to be compared or a column itself based on the query execution plan. You can see this in the example given below. |
81
|
|
|
rows – lists the number of records that were examined to produce the output. This Is another important column worth focusing on optimizing queries, especially for queries that use JOIN and subqueries. |
82
|
|
|
Extra – contains additional information regarding the query execution plan. Values such as “Using temporary”, “Using filesort”, etc. in this column may indicate a troublesome query. For a complete list of possible values and their meaning, check out the MySQL documentation. |
83
|
|
|
* |
84
|
|
|
* |
85
|
|
|
* |
86
|
|
|
* |
87
|
|
|
* @param $builder |
88
|
|
|
*/ |
89
|
|
|
public static function analyzeByBuilder($builder) |
90
|
|
|
{ |
91
|
|
|
//todo fix to use |
92
|
|
|
return self::analyze($builder->toSql(), $builder->bindings()); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* @param $sql |
97
|
|
|
* @param $bindings |
98
|
|
|
* @return array |
99
|
|
|
*/ |
100
|
|
|
public static function analyze($sql, $bindings) |
101
|
|
|
{ |
102
|
|
|
$query = ['sql' => $sql, 'bindings' => $bindings]; |
103
|
|
|
$queryData = DB::connection()->select('EXPLAIN EXTENDED '. $sql, $bindings); |
104
|
|
|
|
105
|
|
|
//todo use |
106
|
|
|
// $ws = DB::connection()->select("SHOW WARNINGS"); |
107
|
|
|
// $sqlOptimized = $ws->fetchColumn(2); |
108
|
|
|
|
109
|
|
|
return ['queryParts' => $queryData, 'query' => $query, 'optimized' => ""]; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @param $builder |
114
|
|
|
* @return mixed |
115
|
|
|
* @throws \Exception |
116
|
|
|
*/ |
117
|
|
|
public static function showOptimizedQueryByBuilder($builder) |
118
|
|
|
{ |
119
|
|
|
self::analyze($builder); |
|
|
|
|
120
|
|
|
|
121
|
|
|
$ws = DB::connection()->getPdo()->prepare("SHOW WARNINGS"); |
122
|
|
|
$ws->execute(); |
123
|
|
|
|
124
|
|
|
return $ws->fetchColumn(2); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* @param $builder |
129
|
|
|
* @return string |
130
|
|
|
*/ |
131
|
|
|
protected static function addBindingsToQueryByBuilder($builder): string |
132
|
|
|
{ |
133
|
|
|
return self::combineQueryAndBindings($builder->toSql(), $builder->getBindings()); |
134
|
|
|
} |
135
|
|
|
} |
This check marks calls to methods that do not seem to exist on an object.
This is most likely the result of a method being renamed without all references to it being renamed likewise.