diff --git a/CHANGELOG-v3.md b/CHANGELOG-v3.md index d161fe4a9ec..fe9c89eeb48 100644 --- a/CHANGELOG-v3.md +++ b/CHANGELOG-v3.md @@ -14,6 +14,7 @@ - `craft\helpers\StringHelper::asciiCharMap()` now has `$flat` and `$language` arguments. - Craft no longer saves new versions of entries when absolutely nothing changed about them in the save request. ([#2923](https://github.com/craftcms/cms/issues/2923)) - `minVersionRequired` is no longer enforced on a plugin when updating it if was coming from a `dev-` branch. +- Improved the performance of element queries when a lot of values were passed into a param, such as `id`, by using `IN()` and `NOT IN()` conditions when possible. ([#2937](https://github.com/craftcms/cms/pull/2937)) ### Deprecated - Deprecated the `customAsciiCharMappings` config setting. (Any corrections to ASCII char mappings should be submitted to [Stringy](https://github.com/danielstjules/Stringy).) diff --git a/src/helpers/Db.php b/src/helpers/Db.php index 24b60e51861..d46bc5c68a1 100644 --- a/src/helpers/Db.php +++ b/src/helpers/Db.php @@ -457,6 +457,9 @@ public static function parseParam(string $column, $value, string $defaultOperato $condition = [$glue]; $isMysql = Craft::$app->getDb()->getIsMysql(); + $inVals = []; + $notInVals = []; + foreach ($value as $val) { self::_normalizeEmptyValue($val); $operator = self::_parseParamOperator($val, $defaultOperator); @@ -522,9 +525,29 @@ public static function parseParam(string $column, $value, string $defaultOperato } } + // ['or', 1, 2, 3] => IN (1, 2, 3) + if ($glue == 'or' && $operator === '=') { + $inVals[] = $val; + continue; + } + + // ['and', '!=1', '!=2', '!=3'] => NOT IN (1, 2, 3) + if ($glue == 'and' && $operator === '!=') { + $notInVals[] = $val; + continue; + } + $condition[] = [$operator, $column, $val]; } + if (!empty($inVals)) { + $condition[] = ['in', $column, $inVals]; + } + + if (!empty($notInVals)) { + $condition[] = ['not in', $column, $notInVals]; + } + return $condition; }