I have one table contains about 3 million rows which structure as follow:
CREATE TABLE `profiles3m` (
`uid` int(10) unsigned NOT NULL,
`birth_date` date NOT NULL,
`gender` tinyint(4) NOT NULL DEFAULT '0',
`country` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'ID',
`city` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'Makassar',
`created_at` timestamp NULL DEFAULT NULL,
`premium` tinyint(4) NOT NULL DEFAULT '0',
`updated_at` timestamp NULL DEFAULT NULL,
`latitude` double NOT NULL DEFAULT '0',
`longitude` double NOT NULL DEFAULT '0',
`orderid` int(11) NOT NULL,
PRIMARY KEY (`uid`),
KEY `idx_composites_latitude_longitude_gender_birth_date_created_at` (`latitude`,`longitude`,`country`,`city`,`gender`,`birth_date`) USING BTREE,
KEY `idx_composites_country_city_gender_birth_date` (`country`,`city`,`gender`,`birth_date`,`orderid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
I am failed to tell MySQL Optimizer to use all columns in the Composite index definition, seems like the optimizer just ignoring the last column as orderid for ordering purpose which is just a copy of uid column as you might know PRIMARY KEY in InnoDB table cannot use to ordering because it may instruct the optimizer to use the PRIMARY KEY as index rather than using our composite Indexes and that is the idea of the creation of orderid column comes from.
The following SQL query, along with the Explain JSON, plus Show Index statement to show all Index Statistics on the table may help to analysing the caused.
SELECT
pro.uid
FROM
`profiles3m` AS pro
WHERE
pro.country = 'INDONESIA'
AND pro.city IN ( 'MAKASSAR' )
AND pro.gender = 0
AND ( pro.birth_date BETWEEN ( NOW()- INTERVAL 35 YEAR ) AND ( NOW()- INTERVAL 25 YEAR ) )
AND pro.orderid > 0
ORDER BY
pro.orderid
LIMIT 30
Explain JSON as follows:
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "45278.73"
},
"ordering_operation": {
"using_filesort": true,
"cost_info": {
"sort_cost": "19051.43"
},
"table": {
"table_name": "pro",
"access_type": "range",
"possible_keys": [
"idx_composites_country_city_gender_birth_date"
],
"key": "idx_composites_country_city_gender_birth_date",
"used_key_parts": [
"country",
"city",
"gender",
"birth_date"
],
"key_length": "488",
"rows_examined_per_scan": 57160,
"rows_produced_per_join": 19051,
"filtered": "33.33",
"using_index": true,
"cost_info": {
"read_cost": "22417.02",
"eval_cost": "3810.29",
"prefix_cost": "26227.30",
"data_read_per_join": "9M"
},
"used_columns": [
"uid",
"birth_date",
"gender",
"country",
"city",
"orderid"
],
"attached_condition": "((`restful`.`pro`.`gender` = 0) and (`restful`.`pro`.`country` = 'INDONESIA') and (`restful`.`pro`.`city` = 'MAKASSAR') and (`restful`.`pro`.`birth_date` between <cache>((now() - interval 35 year)) and <cache>((now() - interval 25 year))) and (`restful`.`pro`.`orderid` > 0))"
}
}
}
}
below is for show index statement :
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 0 | PRIMARY | 1 | uid | A | 2984412 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_latitude_longitude_gender_birth_date_created_at | 1 | latitude | A | 2934360 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_latitude_longitude_gender_birth_date_created_at | 2 | longitude | A | 2984080 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_latitude_longitude_gender_birth_date_created_at | 3 | country | A | 2984080 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_latitude_longitude_gender_birth_date_created_at | 4 | city | A | 2984080 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_latitude_longitude_gender_birth_date_created_at | 5 | gender | A | 2984080 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_latitude_longitude_gender_birth_date_created_at | 6 | birth_date | A | 2984080 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_country_city_gender_birth_date | 1 | country | A | 1 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_country_city_gender_birth_date | 2 | city | A | 14 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_country_city_gender_birth_date | 3 | gender | A | 29 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_country_city_gender_birth_date | 4 | birth_date | A | 362449 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
| 1 | idx_composites_country_city_gender_birth_date | 5 | orderid | A | 2984412 | | | | BTREE |
+------------+----------------------------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+
What really interesting to look in Explain JSON, they told us if the optimizer can only use four part of our indexed and not surprisingly ordering operation is using filesort as you know means slower execution which is bad for application performance.
idx_composites_country_city_gender_birth_date(country,city,gender,birth_date,orderid)
"ordering_operation": {
"using_filesort": true,
.....
"key": "idx_composites_country_city_gender_birth_date",
"used_key_parts": [
"country",
"city",
"gender",
"birth_date"
],
Do i missed something, is it caused by RANGE clause in our WHERE statement?, i've been tested with different combinations of columns in our Composite index sequence for example i am changing orderid column with premium which is a flag column type which only contain 0 and 1, and it worked MySQL Optimizer can utilising all five columns, then why the Optimizer can't do the same with orderid column? is it having to do with Cardinality? i am not so sure, the only thing i can assure is that i must make the ORDER BY working without any impact to the application performance no matter how to do it.
I've been searching the answer in this couple days, but still cannot resolve it. almost forgot to mention MySQL Version in case it helps.
+------------+
| version() |
+------------+
| 5.7.29-log |
+------------+