88namespace Magento \Framework \DB \Logger ;
99
1010use Magento \Framework \App \ResourceConnection ;
11+ use Magento \Framework \Serialize \Serializer \Json ;
1112
1213class QueryIndexAnalyzer implements QueryAnalyzerInterface
1314{
@@ -18,12 +19,18 @@ class QueryIndexAnalyzer implements QueryAnalyzerInterface
1819 */
1920 private int $ smallTableThreshold ;
2021
22+ private array $ analyzerCache = [];
23+
2124 /**
2225 * @param ResourceConnection $resource
26+ * @param Json $serializer
2327 * @param int|null $smallTableThreshold
2428 */
25- public function __construct (private readonly ResourceConnection $ resource , ?int $ smallTableThreshold = null )
26- {
29+ public function __construct (
30+ private readonly ResourceConnection $ resource ,
31+ private readonly Json $ serializer ,
32+ ?int $ smallTableThreshold = null
33+ ) {
2734 if ($ smallTableThreshold !== null ) {
2835 $ this ->smallTableThreshold = $ smallTableThreshold ;
2936 } else {
@@ -45,8 +52,14 @@ public function process(string $sql, array $bindings): array
4552 throw new \InvalidArgumentException ("Can't process query type " );
4653 }
4754
48- $ connection = $ this ->resource ->getConnection ();
49- $ explainOutput = $ connection ->query ('EXPLAIN ' . $ sql , $ bindings )->fetchAll ();
55+ $ cacheKey = $ this ->generateCacheKey ($ sql , $ bindings );
56+ if (isset ($ this ->analyzerCache [$ cacheKey ])) {
57+ $ explainOutput = $ this ->analyzerCache [$ cacheKey ];
58+ } else {
59+ $ connection = $ this ->resource ->getConnection ();
60+ $ explainOutput = $ connection ->query ('EXPLAIN ' . $ sql , $ bindings )->fetchAll ();
61+ $ this ->analyzerCache [$ cacheKey ] = $ explainOutput ;
62+ }
5063
5164 if (empty ($ explainOutput )) {
5265 throw new \InvalidArgumentException ("No 'explain' output available " );
@@ -60,6 +73,18 @@ public function process(string $sql, array $bindings): array
6073 return array_values (array_unique ($ issues ));
6174 }
6275
76+ /**
77+ * Generate a cache key based on the SQL query and its bindings.
78+ *
79+ * @param string $sql
80+ * @param array $bindings
81+ * @return string
82+ */
83+ private function generateCacheKey (string $ sql , array $ bindings ): string
84+ {
85+ return base64_encode (hash ('sha256 ' , $ sql . '| ' . $ this ->serializer ->serialize ($ bindings ), true ));
86+ }
87+
6388 /**
6489 * Detects if a given SQL string is a SELECT query.
6590 *
0 commit comments