Skip to content

Commit

Permalink
Query Plan Analysis: Reduce default numberOfRowsNotRequiringIndex to 0 (
Browse files Browse the repository at this point in the history
#388)

* Reduce DEFAULT_SMALL_TABLE_THRESHOLD to 0

* fix

* cs

* Update RuntimeConfiguration.php

* record

Co-authored-by: Markus Staab <m.staab@complex-it.de>
  • Loading branch information
staabm and clxmstaab authored May 27, 2022
1 parent cde6423 commit 10ee1d3
Show file tree
Hide file tree
Showing 10 changed files with 679 additions and 126 deletions.
481 changes: 481 additions & 0 deletions .phpstan-dba-mysqli.cache

Large diffs are not rendered by default.

14 changes: 10 additions & 4 deletions docs/query-plan-analysis.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The analyzer is reporting problems related to queries not using index, full-tabl

## Signature

`analyzeQueryPlans($numberOfAllowedUnindexedReads = true, $numberOfRowsNotRequiringIndex = QueryPlanAnalyzerMysql::DEFAULT_SMALL_TABLE_THRESHOLD)`
`analyzeQueryPlans($numberOfAllowedUnindexedReads = true, $numberOfRowsNotRequiringIndex = QueryPlanAnalyzer::TABLES_WITHOUT_DATA)`

## Examples

Expand All @@ -26,20 +26,26 @@ $config = new RuntimeConfiguration();
$config->analyzeQueryPlans(100000);
```

To disable the effiency analysis but just check for queries not using indices at all, pass `0`.
To disable the effiency analysis but just check for queries not using indices at all, pass `0`:

```php
$config = new RuntimeConfiguration();
$config->analyzeQueryPlans(0);
```

When running in environments in which only the database schema, but no data is available pass `$numberOfRowsNotRequiringIndex=0`.
When running in environments in which only the database schema, but no data is available pass `$numberOfRowsNotRequiringIndex=0`:

```php
$config = new RuntimeConfiguration();
$config->analyzeQueryPlans(true, 0);
$config->analyzeQueryPlans(true, QueryPlanAnalyzer::TABLES_WITHOUT_DATA);
```

In case you are running a real database with production quality data, you should ignore tables with only few rows, to reduce false positives:

```php
$config = new RuntimeConfiguration();
$config->analyzeQueryPlans(true, QueryPlanAnalyzer::DEFAULT_SMALL_TABLE_THRESHOLD);
```

**Note:** For a meaningful performance analysis it is vital to utilize a database, which containts data and schema as similar as possible to the production database.

Expand Down
22 changes: 22 additions & 0 deletions src/Analyzer/QueryPlanAnalyzer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace staabm\PHPStanDba\Analyzer;

final class QueryPlanAnalyzer
{
/**
* number of unindexed reads allowed before a query is considered inefficient.
*/
public const DEFAULT_UNINDEXED_READS_THRESHOLD = 100000;
/**
* allows analyzing queries even on empty database schemas.
*/
public const TABLES_WITHOUT_DATA = 0;
/**
* max number of rows in a table, for which we don't report errors, because using a index/table-scan wouldn't improve performance.
* requires production quality data in the database at analysis time.
*/
public const DEFAULT_SMALL_TABLE_THRESHOLD = 5000;
}
12 changes: 8 additions & 4 deletions src/Analyzer/QueryPlanAnalyzerMysql.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@
final class QueryPlanAnalyzerMysql
{
/**
* number of unindexed reads allowed before a query is considered inefficient.
* @deprecated use QueryPlanAnalyzer::DEFAULT_UNINDEXED_READS_THRESHOLD instead
*/
public const DEFAULT_UNINDEXED_READS_THRESHOLD = 100000;
public const DEFAULT_UNINDEXED_READS_THRESHOLD = QueryPlanAnalyzer::DEFAULT_UNINDEXED_READS_THRESHOLD;
/**
* max number of rows in a table, for which we don't report errors, because using a index/table-scan wouldn't improve performance.
* @deprecated use QueryPlanAnalyzer::TABLES_WITHOUT_DATA instead
*/
public const DEFAULT_SMALL_TABLE_THRESHOLD = 1000;
public const TABLES_WITHOUT_DATA = QueryPlanAnalyzer::TABLES_WITHOUT_DATA;
/**
* @deprecated use QueryPlanAnalyzer::DEFAULT_SMALL_TABLE_THRESHOLD instead
*/
public const DEFAULT_SMALL_TABLE_THRESHOLD = QueryPlanAnalyzer::DEFAULT_SMALL_TABLE_THRESHOLD;

/**
* @var PDO|mysqli
Expand Down
9 changes: 5 additions & 4 deletions src/QueryReflection/RuntimeConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace staabm\PHPStanDba\QueryReflection;

use PHPStan\Php\PhpVersion;
use staabm\PHPStanDba\Analyzer\QueryPlanAnalyzerMysql;
use staabm\PHPStanDba\Analyzer\QueryPlanAnalyzer;

final class RuntimeConfiguration
{
Expand Down Expand Up @@ -109,14 +109,15 @@ public function stringifyTypes(bool $stringify): self
*
* Requires a active database connection.
*
* @param bool|0|positive-int $numberOfAllowedUnindexedReads `true` to enable analysis with QueryPlanAnalyzerMysql::DEFAULT_UNINDEXED_READS_THRESHOLD. `false` to disable analysis.
* @param bool|0|positive-int $numberOfAllowedUnindexedReads `true` to enable analysis with QueryPlanAnalyzer::DEFAULT_UNINDEXED_READS_THRESHOLD. `false` to disable analysis.
* Otherwise the number of reads a query is allowed to execute, before it is considered inefficient.
* `0` disables the efficiency checks but still scans for queries not using an index.
* @param 0|positive-int $numberOfRowsNotRequiringIndex number of reads a query is allowed to execute, without requiring a index
* @param 0|positive-int $numberOfRowsNotRequiringIndex number of reads a query is allowed to execute, without requiring a index.
* for sane defaults see QueryPlanAnalyzer::TABLES_WITHOUT_DATA and QueryPlanAnalyzer::DEFAULT_SMALL_TABLE_THRESHOLD
*
* @return $this
*/
public function analyzeQueryPlans($numberOfAllowedUnindexedReads = true, $numberOfRowsNotRequiringIndex = QueryPlanAnalyzerMysql::DEFAULT_SMALL_TABLE_THRESHOLD): self
public function analyzeQueryPlans($numberOfAllowedUnindexedReads = true, $numberOfRowsNotRequiringIndex = QueryPlanAnalyzer::TABLES_WITHOUT_DATA): self
{
$this->numberOfAllowedUnindexedReads = $numberOfAllowedUnindexedReads;
$this->numberOfRowsNotRequiringIndex = $numberOfRowsNotRequiringIndex;
Expand Down
3 changes: 0 additions & 3 deletions tests/default/config/.phpstan-dba-mysqli.cache

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions tests/default/config/.phpstan-dba-pdo-mysql.cache

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions tests/default/config/.phpunit-phpstan-dba-mysqli.cache

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

153 changes: 153 additions & 0 deletions tests/rules/config/.phpstan-dba-pdo-mysql.cache

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 10ee1d3

Please sign in to comment.