From eb06e315cc18b399baf799994f928030cd90de3d Mon Sep 17 00:00:00 2001 From: i-just Date: Wed, 30 Apr 2025 11:00:24 +0100 Subject: [PATCH 1/4] when deleting by IDs, split the deletion to 1000 per batch --- src/services/Gc.php | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/services/Gc.php b/src/services/Gc.php index 9e1931047be..80540cb72c2 100644 --- a/src/services/Gc.php +++ b/src/services/Gc.php @@ -254,7 +254,9 @@ public function hardDeleteElements(): void ->column(); if (!empty($ids)) { - Db::delete(Table::ELEMENTS, ['id' => $ids]); + foreach (array_chunk($ids, 1000) as $idsChunk) { + Db::delete(Table::ELEMENTS, ['id' => $idsChunk]); + } } } @@ -308,7 +310,9 @@ public function deletePartialElements(string $elementType, string $table, string ->column(); if (!empty($ids)) { - Db::delete(Table::ELEMENTS, ['id' => $ids]); + foreach (array_chunk($ids, 1000) as $idsChunk) { + Db::delete(Table::ELEMENTS, ['id' => $idsChunk]); + } } $this->_stdout("done\n", Console::FG_GREEN); @@ -448,7 +452,9 @@ private function _deleteUnsupportedSiteEntries(): void } if (!empty($deleteIds)) { - Db::delete(Table::ELEMENTS_SITES, ['id' => $deleteIds]); + foreach (array_chunk($deleteIds, 1000) as $deleteIdsChunk) { + Db::delete(Table::ELEMENTS_SITES, ['id' => $deleteIdsChunk]); + } } $this->_stdout("done\n", Console::FG_GREEN); @@ -470,7 +476,9 @@ private function _deleteOrphanedDraftsAndRevisions(): void ->column(); if (!empty($ids)) { - Db::delete($table, ['id' => $ids]); + foreach (array_chunk($ids, 1000) as $idsChunk) { + Db::delete($table, ['id' => $idsChunk]); + } } } @@ -496,7 +504,9 @@ private function _deleteOrphanedRelations(): void ->column(); if (!empty($ids)) { - Db::delete(Table::RELATIONS, ['id' => $ids]); + foreach (array_chunk($ids, 1000) as $idsChunk) { + Db::delete(Table::RELATIONS, ['id' => $idsChunk]); + } } $this->_stdout("done\n", Console::FG_GREEN); @@ -518,7 +528,9 @@ private function _deleteOrphanedStructureElements(): void ->column(); if (!empty($ids)) { - Db::delete(Table::STRUCTUREELEMENTS, ['id' => $ids]); + foreach (array_chunk($ids, 1000) as $idsChunk) { + Db::delete(Table::STRUCTUREELEMENTS, ['id' => $idsChunk]); + } } $this->_stdout("done\n", Console::FG_GREEN); @@ -636,7 +648,9 @@ public function deleteOrphanedFieldLayouts(string $elementType, string $table, s ->column(); if (!empty($ids)) { - Db::delete(Table::FIELDLAYOUTS, ['id' => $ids]); + foreach (array_chunk($ids, 1000) as $idsChunk) { + Db::delete(Table::FIELDLAYOUTS, ['id' => $idsChunk]); + } } $this->_stdout("done\n", Console::FG_GREEN); From 7b2510a92dfeea4306dfc6e4e2cd1083f5832c4d Mon Sep 17 00:00:00 2001 From: i-just Date: Wed, 30 Apr 2025 12:54:46 +0100 Subject: [PATCH 2/4] switch to a variable and up the chunk size --- src/services/Gc.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/services/Gc.php b/src/services/Gc.php index 80540cb72c2..55f4dd6d84f 100644 --- a/src/services/Gc.php +++ b/src/services/Gc.php @@ -79,6 +79,11 @@ class Gc extends Component */ private GeneralConfig $_generalConfig; + /** + * @var int The number of items that should be deleted in a single batch + */ + private int $_chunkSize = 10000; + /** * @inheritdoc */ @@ -254,7 +259,7 @@ public function hardDeleteElements(): void ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, 1000) as $idsChunk) { + foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { Db::delete(Table::ELEMENTS, ['id' => $idsChunk]); } } @@ -310,7 +315,7 @@ public function deletePartialElements(string $elementType, string $table, string ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, 1000) as $idsChunk) { + foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { Db::delete(Table::ELEMENTS, ['id' => $idsChunk]); } } @@ -452,7 +457,7 @@ private function _deleteUnsupportedSiteEntries(): void } if (!empty($deleteIds)) { - foreach (array_chunk($deleteIds, 1000) as $deleteIdsChunk) { + foreach (array_chunk($deleteIds, $this->_chunkSize) as $deleteIdsChunk) { Db::delete(Table::ELEMENTS_SITES, ['id' => $deleteIdsChunk]); } } @@ -476,7 +481,7 @@ private function _deleteOrphanedDraftsAndRevisions(): void ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, 1000) as $idsChunk) { + foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { Db::delete($table, ['id' => $idsChunk]); } } @@ -504,7 +509,7 @@ private function _deleteOrphanedRelations(): void ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, 1000) as $idsChunk) { + foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { Db::delete(Table::RELATIONS, ['id' => $idsChunk]); } } @@ -528,7 +533,7 @@ private function _deleteOrphanedStructureElements(): void ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, 1000) as $idsChunk) { + foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { Db::delete(Table::STRUCTUREELEMENTS, ['id' => $idsChunk]); } } @@ -648,7 +653,7 @@ public function deleteOrphanedFieldLayouts(string $elementType, string $table, s ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, 1000) as $idsChunk) { + foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { Db::delete(Table::FIELDLAYOUTS, ['id' => $idsChunk]); } } From 71b4e16f36e50881fc4baf7a63eb781974e7ad5f Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Thu, 1 May 2025 15:51:20 -0700 Subject: [PATCH 3/4] CHUNK_SIZE --- src/services/Gc.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/services/Gc.php b/src/services/Gc.php index 55f4dd6d84f..699b459802b 100644 --- a/src/services/Gc.php +++ b/src/services/Gc.php @@ -53,6 +53,11 @@ class Gc extends Component */ public const EVENT_RUN = 'run'; + /** + * @var int The number of items that should be deleted in a single batch. + */ + private const CHUNK_SIZE = 10000; + /** * @var int the probability (parts per million) that garbage collection (GC) should be performed * on a request. Defaults to 10, meaning 0.001% chance. @@ -79,11 +84,6 @@ class Gc extends Component */ private GeneralConfig $_generalConfig; - /** - * @var int The number of items that should be deleted in a single batch - */ - private int $_chunkSize = 10000; - /** * @inheritdoc */ @@ -259,7 +259,7 @@ public function hardDeleteElements(): void ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { + foreach (array_chunk($ids, self::CHUNK_SIZE) as $idsChunk) { Db::delete(Table::ELEMENTS, ['id' => $idsChunk]); } } @@ -315,7 +315,7 @@ public function deletePartialElements(string $elementType, string $table, string ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { + foreach (array_chunk($ids, self::CHUNK_SIZE) as $idsChunk) { Db::delete(Table::ELEMENTS, ['id' => $idsChunk]); } } @@ -457,7 +457,7 @@ private function _deleteUnsupportedSiteEntries(): void } if (!empty($deleteIds)) { - foreach (array_chunk($deleteIds, $this->_chunkSize) as $deleteIdsChunk) { + foreach (array_chunk($deleteIds, self::CHUNK_SIZE) as $deleteIdsChunk) { Db::delete(Table::ELEMENTS_SITES, ['id' => $deleteIdsChunk]); } } @@ -481,7 +481,7 @@ private function _deleteOrphanedDraftsAndRevisions(): void ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { + foreach (array_chunk($ids, self::CHUNK_SIZE) as $idsChunk) { Db::delete($table, ['id' => $idsChunk]); } } @@ -509,7 +509,7 @@ private function _deleteOrphanedRelations(): void ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { + foreach (array_chunk($ids, self::CHUNK_SIZE) as $idsChunk) { Db::delete(Table::RELATIONS, ['id' => $idsChunk]); } } @@ -533,7 +533,7 @@ private function _deleteOrphanedStructureElements(): void ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { + foreach (array_chunk($ids, self::CHUNK_SIZE) as $idsChunk) { Db::delete(Table::STRUCTUREELEMENTS, ['id' => $idsChunk]); } } @@ -653,7 +653,7 @@ public function deleteOrphanedFieldLayouts(string $elementType, string $table, s ->column(); if (!empty($ids)) { - foreach (array_chunk($ids, $this->_chunkSize) as $idsChunk) { + foreach (array_chunk($ids, self::CHUNK_SIZE) as $idsChunk) { Db::delete(Table::FIELDLAYOUTS, ['id' => $idsChunk]); } } From f62f59423744cc3102b1b830dadae2668c238863 Mon Sep 17 00:00:00 2001 From: brandonkelly Date: Thu, 1 May 2025 15:52:54 -0700 Subject: [PATCH 4/4] Release note [ci skip] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a81b27b7386..081c178d330 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased - Fixed a bug where admin tables’ pagination footers could be positioned incorrectly in slideouts. ([#17187](https://github.com/craftcms/cms/issues/17187)) +- Fixed a SQL error that could occur when running garbage collection. ([#17197](https://github.com/craftcms/cms/issues/17197)) - Fixed a styling issue. ## 4.15.2 - 2025-04-23