We switched from MariaDB to Mysql 8.0.30 last week and noticed a query that used to take around 300ms now runs for 32 seconds. Debugging has shown that it has to do with the amount of bindings in the prepared statement and that it only shows up since MySQL version 8.0.22, before that on version 8.0.21 the problem did not exist. Changelog says that they changed the way prepared statements are executed, but I can't relate it to what's happening.
If I remove any of the 4 main exists() sub selects, the query executes in around 300ms again. It does not matter which one.
Inserting the values myself and executing the query directly on the query console results in the same ~300ms execution time.
Setting PDO's ATTR_EMULATE_PREPARES to true resolves the issue, but iirc it is discouraged for security reasons.
This also seems to at least temporarily solve the issue but performance is worse than 300ms
mysqlcheck -uroot -p -o --all-databases
For context: These are shopping products that were automatically generated iterating through 4 different attributes and their values ("generator_conditions"). This is the query generated by Laravel 9 on PHP 8.1.1 to find products that match certain generator_condition_values:
select *
from `products`
where exists(select *
from `products` as `laravel_reserved_0`
where `laravel_reserved_0`.`id` = `products`.`parent_id` and `uuid` = ? and
exists(select *
from `categories`
inner join `categories_product` on `categories`.`id` = `category_product`.`category_id`
where `laravel_reserved_0`.`id` = `category_product`.`product_id` and `uuid` = ?) and `laravel_reserved_0`.`deleted_at` is null) and
exists(select *
from `generator_condition_values`
inner join `generator_condition_value_product` on `generator_condition_values`.`id` = `generator_condition_value_product`.`generator_condition_value_id`
where `products`.`id` = `generator_condition_value_product`.`product_id` and
exists(select * from `generator_conditions` where `generator_condition_values`.`generator_condition_id` = `generator_conditions`.`id` and `name` = ?) and `min_value` <= ? and
(`max_value` >= ? or `max_value` is null)) and
exists(select *
from `generator_condition_values`
inner join `generator_condition_value_product` on `generator_condition_values`.`id` = `generator_condition_value_product`.`generator_condition_value_id`
where `products`.`id` = `generator_condition_value_product`.`product_id` and
exists(select * from `generator_conditions` where `generator_condition_values`.`generator_condition_id` = `generator_conditions`.`id` and `name` = ?) and `min_value` <= ? and
(`max_value` >= ? or `max_value` is null)) and
exists(select *
from `generator_condition_values`
inner join `generator_condition_value_product` on `generator_condition_values`.`id` = `generator_condition_value_product`.`generator_condition_value_id`
where `products`.`id` = `generator_condition_value_product`.`product_id` and
exists(select * from `generator_conditions` where `generator_condition_values`.`generator_condition_id` = `generator_conditions`.`id` and `name` = ?) and `single_value` = ?) and
exists(select *
from `generator_condition_values`
inner join `generator_condition_value_product` on `generator_condition_values`.`id` = `generator_condition_value_product`.`generator_condition_value_id`
where `products`.`id` = `generator_condition_value_product`.`product_id` and
exists(select * from `generator_conditions` where `generator_condition_values`.`generator_condition_id` = `generator_conditions`.`id` and `name` = ?) and `single_value` = ?)
Bindings:
$bindings = [
'f607e02a-4003-4852-a72c-42632a5d53a4',
'5b863422-7b7f-4d34-9077-c2712555fa4d',
'device_price',
'1700',
'1700',
'device_age',
0,
0,
'is_refurbished',
'0',
'is_commercial',
'0',
];
Explain result:
[
{
"id": 1,
"select_type": "SIMPLE",
"table": "laravel_reserved_0",
"partitions": null,
"type": "ref",
"possible_keys": "PRIMARY,products_uuid_index",
"key": "products_uuid_index",
"key_len": "144",
"ref": "const",
"rows": 1,
"filtered": 10,
"Extra": "Using where; Start temporary"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "categories",
"partitions": null,
"type": "ref",
"possible_keys": "PRIMARY,categories_uuid_index",
"key": "categories_uuid_index",
"key_len": "144",
"ref": "const",
"rows": 1,
"filtered": 100,
"Extra": "Using index"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "category_product",
"partitions": null,
"type": "eq_ref",
"possible_keys": "PRIMARY,category_product_category_id_index,category_product_product_id_index",
"key": "PRIMARY",
"key_len": "16",
"ref": "shop.categories.id,shop.laravel_reserved_0.id",
"rows": 1,
"filtered": 100,
"Extra": "Using index"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_conditions",
"partitions": null,
"type": "ALL",
"possible_keys": "PRIMARY",
"key": null,
"key_len": null,
"ref": null,
"rows": 4,
"filtered": 25,
"Extra": "Using where; Using join buffer (hash join)"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "products",
"partitions": null,
"type": "ref",
"possible_keys": "PRIMARY,products_parent_id_foreign",
"key": "products_parent_id_foreign",
"key_len": "9",
"ref": "shop.laravel_reserved_0.id",
"rows": 4,
"filtered": 100,
"Extra": null
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_condition_value_product",
"partitions": null,
"type": "ref",
"possible_keys": "PRIMARY,gcv_id_primary,p_id_primary",
"key": "p_id_primary",
"key_len": "8",
"ref": "shop.products.id",
"rows": 4,
"filtered": 100,
"Extra": "Using index"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_condition_values",
"partitions": null,
"type": "eq_ref",
"possible_keys": "PRIMARY,condition_value_unique",
"key": "PRIMARY",
"key_len": "8",
"ref": "shop.generator_condition_value_product.generator_condition_value_id",
"rows": 1,
"filtered": 10,
"Extra": "Using where"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_condition_value_product",
"partitions": null,
"type": "ref",
"possible_keys": "PRIMARY,gcv_id_primary,p_id_primary",
"key": "p_id_primary",
"key_len": "8",
"ref": "shop.products.id",
"rows": 4,
"filtered": 100,
"Extra": "Using index"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_conditions",
"partitions": null,
"type": "eq_ref",
"possible_keys": "PRIMARY",
"key": "PRIMARY",
"key_len": "8",
"ref": "shop.generator_condition_values.generator_condition_id",
"rows": 1,
"filtered": 25,
"Extra": "Using where"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_condition_values",
"partitions": null,
"type": "eq_ref",
"possible_keys": "PRIMARY,condition_value_unique",
"key": "PRIMARY",
"key_len": "8",
"ref": "shop.generator_condition_value_product.generator_condition_value_id",
"rows": 1,
"filtered": 10,
"Extra": "Using where"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_conditions",
"partitions": null,
"type": "eq_ref",
"possible_keys": "PRIMARY",
"key": "PRIMARY",
"key_len": "8",
"ref": "shop.generator_condition_values.generator_condition_id",
"rows": 1,
"filtered": 25,
"Extra": "Using where"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_condition_value_product",
"partitions": null,
"type": "ref",
"possible_keys": "PRIMARY,gcv_id_primary,p_id_primary",
"key": "p_id_primary",
"key_len": "8",
"ref": "shop.products.id",
"rows": 4,
"filtered": 100,
"Extra": "Using index"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_condition_values",
"partitions": null,
"type": "eq_ref",
"possible_keys": "PRIMARY,condition_value_unique",
"key": "PRIMARY",
"key_len": "8",
"ref": "shop.generator_condition_value_product.generator_condition_value_id",
"rows": 1,
"filtered": 13.33,
"Extra": "Using where"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_condition_value_product",
"partitions": null,
"type": "ref",
"possible_keys": "PRIMARY,gcv_id_primary,p_id_primary",
"key": "p_id_primary",
"key_len": "8",
"ref": "shop.products.id",
"rows": 4,
"filtered": 100,
"Extra": "Using index"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_conditions",
"partitions": null,
"type": "eq_ref",
"possible_keys": "PRIMARY",
"key": "PRIMARY",
"key_len": "8",
"ref": "shop.generator_condition_values.generator_condition_id",
"rows": 1,
"filtered": 25,
"Extra": "Using where"
},
{
"id": 1,
"select_type": "SIMPLE",
"table": "generator_condition_values",
"partitions": null,
"type": "eq_ref",
"possible_keys": "PRIMARY,condition_value_unique",
"key": "PRIMARY",
"key_len": "8",
"ref": "shop.generator_condition_value_product.generator_condition_value_id",
"rows": 1,
"filtered": 5,
"Extra": "Using where; End temporary"
}
]
Any idea why just a few more bindings completely ruin performance? If the actual table structure is needed for context please let me know and I'll add it.
Thanks!