- Affected Version
- WoltLab Suite 5.4
- Affected App
- WoltLab Suite Forum
Nach längeren suchen ist uns aufgefallen das der Query
SELECT COUNT(*) AS posts
FROM wbb2_post post
WHERE post.threadID = '430' AND post.isDisabled = 0 AND post.isDeleted = 0 AND (time < '1469119244' OR (time = '1469119244' AND postID < '1640234') OR postID = '1640234')
Extrem lange benötigt zum ausführen
Wie man im Log sehen kann, verwendet dieser Query keinen Index und durchsucht die komplette Datenbank
# Time: 221018 12:41:37
# User@Host: gekürzt
# Thread_id: 1603266 Schema: Datenbank_name QC_hit: No
# Query_time: 13.866583 Lock_time: 0.000033 Rows_sent: 1 Rows_examined: 3415846
# Rows_affected: 0 Bytes_sent: 68
SET timestamp=1666089697;
SELECT COUNT(*) AS posts
FROM wbb2_post post
WHERE post.threadID = '430' AND post.isDisabled = 0 AND post.isDeleted = 0 AND (time < '1469119244' OR (time = '1469119244' AND postID < '1640234') OR postID = '1640234') -- '....url....';
Ich habe dadrauf hin natürlich überprüft ob die Index vorhanden sind, und das ist der Fall.
Dies ist der DDL zu der Tabelle
CREATE TABLE `wbb2_post` (
`postID` int(10) NOT NULL AUTO_INCREMENT,
`threadID` int(10) NOT NULL,
`userID` int(10) DEFAULT NULL,
`username` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`subject` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`message` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
`time` int(10) NOT NULL DEFAULT 0,
`isDeleted` tinyint(1) NOT NULL DEFAULT 0,
`isDisabled` tinyint(1) NOT NULL DEFAULT 0,
`isClosed` tinyint(1) NOT NULL DEFAULT 0,
`editorID` int(10) DEFAULT NULL,
`editor` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`lastEditTime` int(10) NOT NULL DEFAULT 0,
`editCount` mediumint(7) NOT NULL DEFAULT 0,
`editReason` mediumtext COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`lastVersionTime` int(10) NOT NULL DEFAULT 0,
`attachments` smallint(5) NOT NULL DEFAULT 0,
`pollID` int(10) DEFAULT NULL,
`enableHtml` tinyint(1) NOT NULL DEFAULT 0,
`ipAddress` varchar(39) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`cumulativeLikes` mediumint(7) NOT NULL DEFAULT 0,
`deleteTime` int(10) NOT NULL DEFAULT 0,
`enableTime` int(10) NOT NULL DEFAULT 0,
`hasEmbeddedObjects` tinyint(1) NOT NULL DEFAULT 0,
`isAnonymized` tinyint(1) DEFAULT 0,
`isOfficial` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`postID`),
KEY `threadID` (`threadID`,`userID`),
KEY `threadID_2` (`threadID`,`isDeleted`,`isDisabled`,`time`),
KEY `isDeleted` (`isDeleted`),
KEY `isDisabled` (`isDisabled`),
KEY `ipAddress` (`ipAddress`),
KEY `time` (`time`),
KEY `enableTime` (`enableTime`),
KEY `2e8cc4cbdaac33da9cccbb86298a3d0e_fk` (`userID`),
KEY `779d84d762b0e57bf1863fe49a0c4f8e_fk` (`editorID`),
KEY `8931e5250ede90c9a62a5e28343c6e0e_fk` (`pollID`),
KEY `userToPost` (`userID`,`isDeleted`,`isDisabled`,`threadID`),
KEY `thread_3` (`threadID`,`isDisabled`,`userID`,`time`),
KEY `isOfficial` (`threadID`,`isOfficial`),
CONSTRAINT `2e8cc4cbdaac33da9cccbb86298a3d0e_fk` FOREIGN KEY (`userID`) REFERENCES `wcf2_user` (`userID`) ON DELETE SET NULL,
CONSTRAINT `779d84d762b0e57bf1863fe49a0c4f8e_fk` FOREIGN KEY (`editorID`) REFERENCES `wcf2_user` (`userID`) ON DELETE SET NULL,
CONSTRAINT `8931e5250ede90c9a62a5e28343c6e0e_fk` FOREIGN KEY (`pollID`) REFERENCES `wcf2_poll` (`pollID`) ON DELETE SET NULL,
CONSTRAINT `cd890d9ca4f88b5c82f5011128400034_fk` FOREIGN KEY (`threadID`) REFERENCES `wbb2_thread` (`threadID`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3436208 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Display More
Ausgabe von Explain
{
"query_block": {
"select_id": 1,
"r_loops": 1,
"r_total_time_ms": 40018,
"table": {
"table_name": "post",
"access_type": "index_merge",
"possible_keys": [
"PRIMARY",
"threadID",
"threadID_2",
"isDeleted",
"isDisabled",
"time",
"thread_3",
"isOfficial"
],
"key_length": "1,1,5,5",
"index_merge": {
"union": {
"intersect": {
"range": {
"key": "isDeleted",
"used_key_parts": ["isDeleted"]
},
"range": {
"key": "isDisabled",
"used_key_parts": ["isDisabled"]
}
},
"intersect": {
"range": {
"key": "isDeleted",
"used_key_parts": ["isDeleted", "postID"]
},
"range": {
"key": "isDisabled",
"used_key_parts": ["isDisabled", "postID"]
}
}
}
},
"r_loops": 1,
"rows": 2,
"r_rows": 3.42e6,
"r_total_time_ms": 29563,
"filtered": 0.9814,
"r_filtered": 0.1602,
"attached_condition": "post.threadID = 430 and post.isDisabled = 0 and post.isDeleted = 0 and (post.`time` < 1469119244 or post.`time` = 1469119244 and post.postID < 1640234 or post.postID = 1650234)"
}
}
}
Display More
Ich habe dies in einigen Test-Foren gegen getestet, dort werden, die Index jedoch richtig im Query verwendet, nur in dieser Datenbank nicht.
Der Query-Optimizer verwendet jedoch manchmal, den richtigen Index.(threadID_2)
Wenn hier einUSE INDEX(threadID_2) verwendet werden würde, müsste der Query-Optimizer hier nicht abwägen ob dies sinnvoll oder nicht ist die ganze Datenbank zu durch suchen. Bei kleinen Tabellen ist dies kein Problem, aber sobald die Tabelle mehrere Millionen Einträge hat, hingegen nicht mehr, dann dauert der Query mehrere Sekunden. Würde der Query nur einmal ausgeführt werden müssen, wäre es okay, aber dies kann durch jeden Benutzer ausgeführt werden.