We have three Percona XtraDB nodes arranged in a master-master replication topology.
One of our databases contains a heavily utilized table. This table has multiple indexes, as well as a few foreign keys and their corresponding indexes.
Output of SHOW CREATE TABLE
:
CREATE TABLE `malfunctions` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`parent_id` bigint unsigned DEFAULT NULL,
`merge_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`uuid` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`status_id` bigint unsigned DEFAULT NULL,
`insphire_workorder_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`device_system_id` bigint unsigned DEFAULT NULL,
`system_id` bigint unsigned DEFAULT NULL,
`malfunction_analyze_id` bigint unsigned DEFAULT NULL,
`service_company_id` bigint unsigned DEFAULT NULL,
`security_company_id` bigint unsigned DEFAULT NULL,
`type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`priority` int unsigned DEFAULT NULL,
`reporter` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `malfunctions_uuid_unique` (`uuid`),
KEY `malfunctions_type_index` (`type`),
KEY `malfunctions_device_system_id_foreign` (`device_system_id`),
KEY `malfunctions_system_id_foreign` (`system_id`),
KEY `malfunctions_malfunction_analyze_id_foreign` (`malfunction_analyze_id`),
KEY `malfunctions_service_company_id_foreign` (`service_company_id`),
KEY `malfunctions_security_company_id_foreign` (`security_company_id`),
KEY `malfunctions_insphire_workorder_id_index` (`insphire_workorder_id`),
KEY `malfunctions_merge_id_index` (`merge_id`),
KEY `malfunctions_parent_id_index` (`parent_id`),
KEY `malfunctions_priority_index` (`priority`),
KEY `malfunctions_status_id_priority_deleted_at_index` (`status_id`,`priority`,`deleted_at`),
KEY `malfunctions_status_id_foreign` (`status_id`),
KEY `idx_malfunctions_query` (`deleted_at`,`priority`,`status_id`,`device_system_id`,`system_id`,`malfunction_analyze_id`),
CONSTRAINT `malfunctions_device_system_id_foreign` FOREIGN KEY (`device_system_id`) REFERENCES `device_system` (`id`) ON DELETE SET NULL,
CONSTRAINT `malfunctions_ibfk_1` FOREIGN KEY (`status_id`) REFERENCES `malfunction_statuses` (`id`),
CONSTRAINT `malfunctions_malfunction_analyze_id_foreign` FOREIGN KEY (`malfunction_analyze_id`) REFERENCES `malfunction_analyzes` (`id`) ON DELETE SET NULL,
CONSTRAINT `malfunctions_security_company_id_foreign` FOREIGN KEY (`security_company_id`) REFERENCES `security_companies` (`id`) ON DELETE SET NULL,
CONSTRAINT `malfunctions_service_company_id_foreign` FOREIGN KEY (`service_company_id`) REFERENCES `service_companies` (`id`) ON DELETE SET NULL,
CONSTRAINT `malfunctions_system_id_foreign` FOREIGN KEY (`system_id`) REFERENCES `systems` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
The offending query:
SELECT
*
FROM
`malfunctions`
WHERE
EXISTS (
SELECT
*
FROM
`malfunction_statuses`
WHERE
`malfunctions`.`status_id` = `malfunction_statuses`.`id`
and(`active` = 1
OR `name` = 'processing_in_chain')
AND `malfunction_statuses`.`deleted_at` IS NULL)
AND `priority` > 0
AND `device_system_id` = 39967
AND `system_id` = 4135
AND `malfunction_analyze_id` = 6
AND `id` <> 92250574
AND `malfunctions`.`deleted_at` IS NULL;
When running the query on the second node (sql002
), the query planner decides to use the index malfunctions_status_id_priority_deleted_at_index
which results in a query execution time of 1 row in set (1.22 sec)
.
When running the query on the first or third node (sql001
and sql003
), the query planner decides to use the index malfunctions_status_id_foreign
which results in a query execution time of 1 row in set (28.76 sec)
.
We obviously want to use the index that the sql002
server automatically uses, and I'm aware I can force MySQL to use that index, but there are more cases the other 2 servers choose the wrong index.
What we have tried:
Executing
ANALYZE TABLE malfunctions
on all nodes (even though 1 should be enough if I'm not mistaken), but this does not change anything.
Re-initializing one of the nodes by letting them rejoin the cluster as a clean node which triggers a full state-transfer.
We now force our application to connect to the fast node, but that's obviously not the right decision.
Why does this happen, and how can we resolve it?
EXPLAIN SELECT ...
for each server.AND
is the most selective?