How to improve this query mysql and rails 5 - mysql

We have three tables users, stores and store_customer_associations, where a user can be a customer for many stores.
I've tried to place another index in primary key but without success (and other too).
(currently these are our indexes in each table)
mysql> SHOW INDEXES FROM store_customer_associations;
+-------+------------+-------------------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-------------------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| users | 0 | PRIMARY | 1 | id | A | 9386515 | NULL | NULL | | BTREE | | |
| users | 0 | tmp_idx_users_id | 1 | id | A | 9386515 | NULL | NULL | | BTREE | | |
+-------+------------+-------------------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
10 rows in set (0.00 sec)
mysql> SHOW INDEXES FROM store_customer_associations;
+-----------------------------+------------+-----------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------------------------+------------+-----------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| store_customer_associations | 0 | PRIMARY | 1 | id | A | 51298761 | NULL | NULL | | BTREE | | |
| store_customer_associations | 1 | index_store_customer_associations_on_store_id | 1 | store_id | A | 50096 | NULL | NULL | YES | BTREE | | |
| store_customer_associations | 1 | index_store_customer_associations_on_user_id | 1 | user_id | A | 25649380 | NULL | NULL | YES | BTREE | | |
+-----------------------------+------------+-----------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
We are using rails 5.1 (this is a big rails 4 legacy database).
Then we need to make this query fast:
SELECT COUNT(*)
FROM `users`
INNER JOIN `store_customer_associations`
ON `users`.`id` = `store_customer_associations`.`user_id`
WHERE `store_customer_associations`.`store_id` = STORE_ID;
+----------+
| COUNT(*) |
+----------+
| 1997632 |
+----------+
1 row in set (6.64 sec)
mysql> EXPLAIN SELECT COUNT(*)
FROM `users`
INNER JOIN `store_customer_associations`
ON `users`.`id` = `store_customer_associations`.`user_id`
WHERE `store_customer_associations`.`store_id` = STORE_ID;
+------+-------------+-----------------------------+--------+--------------------------------------------------------------------------------------------+-----------------------------------------------+---------+---------------------------------------------------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------------------------+--------+--------------------------------------------------------------------------------------------+-----------------------------------------------+---------+---------------------------------------------------------+---------+-------------+
| 1 | SIMPLE | store_customer_associations | ref | index_store_customer_associations_on_store_id,index_store_customer_associations_on_user_id | index_store_customer_associations_on_store_id | 5 | const | 4401812 | Using where |
| 1 | SIMPLE | users | eq_ref | PRIMARY,tmp_idx_users_id | PRIMARY | 4 | trustvox_production.store_customer_associations.user_id | 1 | Using index |
+------+-------------+-----------------------------+--------+--------------------------------------------------------------------------------------------+-----------------------------------------------+---------+---------------------------------------------------------+---------+-------------+
2 rows in set (0.00 sec)
UPDATE 1
mysql> EXPLAIN SELECT COUNT(*)
FROM `users`
INNER JOIN `store_customer_associations`
ON `users`.`id` = `store_customer_associations`.`user_id`
WHERE `store_customer_associations`.`store_id` = STORE_ID;
+------+-------------+-----------------------------+--------+-------------------------------------------------------------------------------------------------------------+-----------------------------------------------+---------+---------------------------------------------------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------------------------+--------+-------------------------------------------------------------------------------------------------------------+-----------------------------------------------+---------+---------------------------------------------------------+---------+-------------+
| 1 | SIMPLE | store_customer_associations | ref | index_store_customer_associations_on_store_id,index_store_customer_associations_on_user_id,user_id_store_id | index_store_customer_associations_on_store_id | 5 | const | 4401812 | Using where |
| 1 | SIMPLE | users | eq_ref | PRIMARY,tmp_idx_users_id | PRIMARY | 4 | trustvox_production.store_customer_associations.user_id | 1 | Using index |
+------+-------------+-----------------------------+--------+-------------------------------------------------------------------------------------------------------------+-----------------------------------------------+---------+---------------------------------------------------------+---------+-------------+
2 rows in set (0.00 sec)
UPDATE 2
mysql> SELECT COUNT(*)
FROM users
INNER JOIN store_customer_associations
FORCE INDEX FOR JOIN (PRIMARY, user_id_store_id)
ON users.id = store_customer_associations.user_id
WHERE store_customer_associations.store_id = STORE_ID;
+----------+
| COUNT(*) |
+----------+
| 1997632 |
+----------+
1 row in set (28.90 sec)
mysql> EXPLAIN SELECT COUNT(*)
FROM users
INNER JOIN store_customer_associations
FORCE INDEX FOR JOIN (PRIMARY, user_id_store_id)
ON users.id = store_customer_associations.user_id
WHERE store_customer_associations.store_id = STORE_ID;
+------+-------------+-----------------------------+-------+--------------------------+------------------+---------+------------------------------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------------------------+-------+--------------------------+------------------+---------+------------------------------------+---------+-------------+
| 1 | SIMPLE | users | index | PRIMARY,tmp_idx_users_id | tmp_idx_users_id | 4 | NULL | 8675689 | Using index |
| 1 | SIMPLE | store_customer_associations | ref | user_id_store_id | user_id_store_id | 10 | trustvox_production.users.id,const | 1 | Using index |
+------+-------------+-----------------------------+-------+--------------------------+------------------+---------+------------------------------------+---------+-------------+
2 rows in set (0.00 sec)
mysql>
UPDATE 3
mysql> EXPLAIN SELECT COUNT(*)
FROM users
INNER JOIN
( SELECT *
FROM store_customer_associations
WHERE store_id = 75856
) sca ON users.id = sca.user_id;
+------+-------------+-----------------------------+--------+-------------------------------------------------------------------------------------------------------------+-----------------------------------------------+---------+---------------------------------------------------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------------------------+--------+-------------------------------------------------------------------------------------------------------------+-----------------------------------------------+---------+---------------------------------------------------------+---------+-------------+
| 1 | SIMPLE | store_customer_associations | ref | index_store_customer_associations_on_store_id,index_store_customer_associations_on_user_id,user_id_store_id | index_store_customer_associations_on_store_id | 5 | const | 4401812 | Using where |
| 1 | SIMPLE | users | eq_ref | PRIMARY,tmp_idx_users_id | PRIMARY | 4 | trustvox_production.store_customer_associations.user_id | 1 | Using index |
+------+-------------+-----------------------------+--------+-------------------------------------------------------------------------------------------------------------+-----------------------------------------------+---------+---------------------------------------------------------+---------+-------------+
UPDATE 4
mysql> ALTER TABLE store_customer_associations DROP INDEX index_store_customer_associations_on_store_id;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> ALTER TABLE store_customer_associations DROP INDEX index_store_customer_associations_on_user_id;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> CREATE INDEX index_on_store_id_and_user_id ON store_customer_associations (store_id, user_id);
Query OK, 0 rows affected (45.95 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> CREATE INDEX index_store_customer_associations_on_user_id ON store_customer_associations(user_id);
Query OK, 0 rows affected (33.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> CREATE INDEX index_store_customer_associations_on_store_id ON store_customer_associations(store_id);
Query OK, 0 rows affected (38.58 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> SHOW INDEXES FROM store_customer_associations;
+-----------------------------+------------+-----------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------------------------+------------+-----------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| store_customer_associations | 0 | PRIMARY | 1 | id | A | 10305620 | NULL | NULL | | BTREE | | |
| store_customer_associations | 1 | index_on_store_id_and_user_id | 1 | store_id | A | 8244 | NULL | NULL | YES | BTREE | | |
| store_customer_associations | 1 | index_on_store_id_and_user_id | 2 | user_id | A | 10305620 | NULL | NULL | YES | BTREE | | |
| store_customer_associations | 1 | index_store_customer_associations_on_user_id | 1 | user_id | A | 10305620 | NULL | NULL | YES | BTREE | | |
| store_customer_associations | 1 | index_store_customer_associations_on_store_id | 1 | store_id | A | 6424 | NULL | NULL | YES | BTREE | | |
+-----------------------------+------------+-----------------------------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
5 rows in set (0.00 sec)

store_customer_associations: INDEX(store_id, user_id) -- "covering"
store_id is first -- to handle the WHERE; user_id is added so that the only the index need by touched.
A tutorial that lets you discover the INDEX yourself: http://mysql.rjweb.org/doc.php/index_cookbook_mysql

U need to make index for 2 parameters for store_curstometer_associations because in query index is not because where part.
create index user_id_store_id on store_customer_associations (user_id, store_id)
Should help u out
Example
mysql> show indexes from api_plexts;
+------------+------------+----------------------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+----------------------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| api_plexts | 0 | PRIMARY | 1 | id | A | 206318 | NULL | NULL | | BTREE | | |
| api_plexts | 0 | index_api_plexts_on_guid | 1 | guid | A | 215475 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | index_api_plexts_on_api_agent_id | 1 | api_agent_id | A | 1565 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | index_api_plexts_on_from_api_portal_id | 1 | from_api_portal_id | A | 11401 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | index_api_plexts_on_to_api_portal_id | 1 | to_api_portal_id | A | 9566 | NULL | NULL | YES | BTREE | | |
+------------+------------+----------------------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
5 rows in set (0.00 sec)
mysql> show indexes from api_portals;
+-------------+------------+--------------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------------+------------+--------------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| api_portals | 0 | PRIMARY | 1 | id | A | 20530 | NULL | NULL | | BTREE | | |
| api_portals | 0 | index_api_portals_on_guid | 1 | guid | A | 19891 | NULL | NULL | YES | BTREE | | |
| api_portals | 1 | index_api_portals_on_owner_agent_id | 1 | owner_agent_id | A | 718 | NULL | NULL | YES | BTREE | | |
| api_portals | 1 | index_api_portals_on_api_map_tile_id | 1 | api_map_tile_id | A | 5480 | NULL | NULL | YES | BTREE | | |
+-------------+------------+--------------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
explain select count(*) from api_portals ap JOIN api_plexts al FORCE INDEX FOR JOIN (PRIMARY) on ap.id = al.from_api_portal_id where al.api_agent_id = 2\G;
mysql> show indexes from api_plexts;
+------------+------------+----------------------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+----------------------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| api_plexts | 0 | PRIMARY | 1 | id | A | 206318 | NULL | NULL | | BTREE | | |
| api_plexts | 0 | index_api_plexts_on_guid | 1 | guid | A | 215475 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | index_api_plexts_on_api_agent_id | 1 | api_agent_id | A | 1565 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | index_api_plexts_on_from_api_portal_id | 1 | from_api_portal_id | A | 11401 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | index_api_plexts_on_to_api_portal_id | 1 | to_api_portal_id | A | 9566 | NULL | NULL | YES | BTREE | | |
+------------+------------+----------------------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
5 rows in set (0.00 sec)
mysql> show indexes from api_portals;
+-------------+------------+--------------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------------+------------+--------------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| api_portals | 0 | PRIMARY | 1 | id | A | 20530 | NULL | NULL | | BTREE | | |
| api_portals | 0 | index_api_portals_on_guid | 1 | guid | A | 19891 | NULL | NULL | YES | BTREE | | |
| api_portals | 1 | index_api_portals_on_owner_agent_id | 1 | owner_agent_id | A | 718 | NULL | NULL | YES | BTREE | | |
| api_portals | 1 | index_api_portals_on_api_map_tile_id | 1 | api_map_tile_id | A | 5480 | NULL | NULL | YES | BTREE | | |
+-------------+------------+--------------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
mysql> explain select count(*) from api_portals ap JOIN api_plexts al on ap.id = al.from_api_portal_id where al.api_agent_id = 2;
+----+-------------+-------+------------+--------+-------------------------------------------------------------------------+----------------------------------+---------+-------------------------------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+-------------------------------------------------------------------------+----------------------------------+---------+-------------------------------+------+----------+--------------------------+
| 1 | SIMPLE | al | NULL | ref | index_api_plexts_on_api_agent_id,index_api_plexts_on_from_api_portal_id | index_api_plexts_on_api_agent_id | 5 | const | 271 | 100.00 | Using where |
| 1 | SIMPLE | ap | NULL | eq_ref | PRIMARY | PRIMARY | 8 | ingress.al.from_api_portal_id | 1 | 100.00 | Using where; Using index |
+----+-------------+-------+------------+--------+-------------------------------------------------------------------------+----------------------------------+---------+-------------------------------+------+----------+--------------------------+
this is exactly your case U can see using where
mysql> create index testime on api_plexts (api_agent_id, from_api_portal_id); Query OK, 0 rows affected (3.71 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show indexes from api_plexts;
+------------+------------+----------------------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+----------------------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| api_plexts | 0 | PRIMARY | 1 | id | A | 200644 | NULL | NULL | | BTREE | | |
| api_plexts | 0 | index_api_plexts_on_guid | 1 | guid | A | 209549 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | index_api_plexts_on_api_agent_id | 1 | api_agent_id | A | 1522 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | index_api_plexts_on_from_api_portal_id | 1 | from_api_portal_id | A | 11087 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | index_api_plexts_on_to_api_portal_id | 1 | to_api_portal_id | A | 9303 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | testime | 1 | api_agent_id | A | 1817 | NULL | NULL | YES | BTREE | | |
| api_plexts | 1 | testime | 2 | from_api_portal_id | A | 52277 | NULL | NULL | YES | BTREE | | |
+------------+------------+----------------------------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
7 rows in set (0.00 sec)
VOILA!!!
mysql> explain select count(*) from api_portals ap JOIN api_plexts al on ap.id = al.from_api_portal_id where al.api_agent_id = 2\G; *************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: al
partitions: NULL
type: ref
possible_keys: index_api_plexts_on_api_agent_id,index_api_plexts_on_from_api_portal_id,testime
key: testime
key_len: 5
ref: const
rows: 271
filtered: 100.00
Extra: Using where; Using index
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: ap
partitions: NULL
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 8
ref: ingress.al.from_api_portal_id
rows: 1
filtered: 100.00
Extra: Using where; Using index
2 rows in set, 1 warning (0.00 sec)

Related

Slow COUNT(*) with JSON_SEARCH

I have a table that stores tags in the JSON format for each page. Current table has about 1,000,000 records.
When I run
SELECT COUNT(*) FROM alltags WHERE tagtype = 'pages' AND JSON_SEARCH(tags, 'one', 'Hampden') IS NOT NULL;
the query takes about 20 seconds
+----------+
| COUNT(*) |
+----------+
| 23500 |
+----------+
1 row in set (19.20 sec)
The query is slow regardless if I use InnoDB or MyISAM engine.
I got indexes for tagtype, tags and tagtype with tags columns. I need the exact number of results for pagination. Is there a way I can speed up the SELECT COUNT query? Selecting actual data is pretty instant.
SELECT id FROM alltags WHERE tagtype = 'pages' AND JSON_SEARCH(tags, 'one', 'Hampden') IS NOT NULL LIMIT 0,10;
+------+
| id |
+------+
| 5072 |
| 5075 |
| 5078 |
| 5081 |
| 5084 |
| 5087 |
| 5090 |
| 5093 |
| 5096 |
| 5099 |
+------+
10 rows in set (0.01 sec)
These are the indexes
SHOW INDEX FROM alltags;
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| alltags | 0 | PRIMARY | 1 | id | A | 896649 | NULL | NULL | | BTREE | | |
| alltags | 1 | tagtype | 1 | tagtype | A | 2 | NULL | NULL | | BTREE | | |
| alltags | 1 | keyword | 1 | keyword | A | 33 | NULL | NULL | | BTREE | | |
| alltags | 1 | tags | 1 | tags | A | 89665 | NULL | NULL | YES | BTREE | | |
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
EXPLAIN results:
Select data
EXPLAIN SELECT id FROM alltags WHERE tagtype = 'pages' AND JSON_SEARCH(tags, 'one', 'Hampden') IS NOT NULL;
+----+-------------+---------+------------+------+---------------+---------+---------+-------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+--------+----------+-------------+
| 1 | SIMPLE | alltags | NULL | ref | tagtype | tagtype | 7 | const | 892372 | 100.00 | Using where |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
Select count
EXPLAIN SELECT COUNT(*) FROM alltags WHERE tagtype = 'pages' AND JSON_SEARCH(tags, 'one', 'Hampden') IS NOT NULL;
+----+-------------+---------+------------+------+---------------+---------+---------+-------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+--------+----------+-------------+
| 1 | SIMPLE | alltags | NULL | ref | tagtype | tagtype | 7 | const | 892372 | 100.00 | Using where |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

Why is MySQL removing an existing index when adding a new one?

I'm adding a combined index to a table, but that index removes an already existing index (see how fk_service_catalog_parameter_component disappears). Any idea why?
mysql> show indexes from service_catalog_parameter;
+---------------------------+------------+----------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------------------+------------+----------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| service_catalog_parameter | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| service_catalog_parameter | 1 | fk_service_catalog_parameter_resource | 1 | resource_id | A | 0 | NULL | NULL | YES | BTREE | | |
| service_catalog_parameter | 1 | fk_service_catalog_parameter_component | 1 | component_id | A | 0 | NULL | NULL | YES | BTREE | | |
+---------------------------+------------+----------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
mysql> ALTER TABLE `service_catalog_parameter` ADD UNIQUE INDEX `resource_parameter_component_unique` (`component_id`, `resource_id`, `parameter_name`);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show indexes from service_catalog_parameter;
+---------------------------+------------+---------------------------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------------------+------------+---------------------------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| service_catalog_parameter | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| service_catalog_parameter | 0 | resource_parameter_component_unique | 1 | component_id | A | 0 | NULL | NULL | YES | BTREE | | |
| service_catalog_parameter | 0 | resource_parameter_component_unique | 2 | resource_id | A | 0 | NULL | NULL | YES | BTREE | | |
| service_catalog_parameter | 0 | resource_parameter_component_unique | 3 | parameter_name | A | 0 | NULL | NULL | | BTREE | | |
| service_catalog_parameter | 1 | fk_service_catalog_parameter_resource | 1 | resource_id | A | 0 | NULL | NULL | YES | BTREE | | |
+---------------------------+------------+---------------------------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
5 rows in set (0.00 sec)
mysql>
My head totally blows up when I change the order of the columns in the index.
mysql> show indexes from service_catalog_parameter;
+---------------------------+------------+----------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------------------+------------+----------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| service_catalog_parameter | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| service_catalog_parameter | 1 | fk_service_catalog_parameter_resource | 1 | resource_id | A | 0 | NULL | NULL | YES | BTREE | | |
| service_catalog_parameter | 1 | fk_service_catalog_parameter_component | 1 | component_id | A | 0 | NULL | NULL | YES | BTREE | | |
+---------------------------+------------+----------------------------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.01 sec)
mysql> ALTER TABLE `service_catalog_parameter` ADD UNIQUE INDEX `resource_parameter_component_unique` (`parameter_name`, `component_id`, `resource_id`);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show indexes from service_catalog_parameter;
+---------------------------+------------+----------------------------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------------------+------------+----------------------------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| service_catalog_parameter | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | |
| service_catalog_parameter | 0 | resource_parameter_component_unique | 1 | parameter_name | A | 0 | NULL | NULL | | BTREE | | |
| service_catalog_parameter | 0 | resource_parameter_component_unique | 2 | component_id | A | 0 | NULL | NULL | YES | BTREE | | |
| service_catalog_parameter | 0 | resource_parameter_component_unique | 3 | resource_id | A | 0 | NULL | NULL | YES | BTREE | | |
| service_catalog_parameter | 1 | fk_service_catalog_parameter_resource | 1 | resource_id | A | 0 | NULL | NULL | YES | BTREE | | |
| service_catalog_parameter | 1 | fk_service_catalog_parameter_component | 1 | component_id | A | 0 | NULL | NULL | YES | BTREE | | |
+---------------------------+------------+----------------------------------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
6 rows in set (0.00 sec)
mysql>

Join not using index and the indexes are exactly the same

I am not sure why this query isn't using an index on the table world_cities. The indexes are the same and in the same order. The data types are of the same type and same length. The only difference is the key_name.
So why does it not use the key?
if I run the query I get: 318824 rows in set (2 min 51.30 sec)
Here is what I have done:
explain select * from zip_codes zc
inner join world_cities wc on
zc.city = wc.city
and zc.country = wc.country
and zc.region = wc.region;
+----+-------------+-------+------+---------------------+---------------------+---------+---------------------------------------------------------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------------+---------------------+---------+---------------------------------------------------------------+---------+-------------+
| 1 | SIMPLE | wc | ALL | city_country_region | NULL | NULL | NULL | 3173958 | |
| 1 | SIMPLE | zc | ref | country_region_city | country_region_city | 165 | largedbapi.wc.city,largedbapi.wc.country,largedbapi.wc.region | 1 | Using where |
+----+-------------+-------+------+---------------------+---------------------+---------+---------------------------------------------------------------+---------+-------------+
mysql> show indexes from world_cities where Key_name like '%city%';
+--------------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| world_cities | 1 | city_country_region | 1 | city | A | NULL | NULL | NULL | YES | BTREE | |
| world_cities | 1 | city_country_region | 2 | country | A | NULL | NULL | NULL | YES | BTREE | |
| world_cities | 1 | city_country_region | 3 | region | A | NULL | NULL | NULL | YES | BTREE | |
+--------------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
mysql> show indexes from zip_codes where Key_name like '%city%';
+-----------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-----------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| zip_codes | 1 | country_region_city | 1 | city | A | 218424 | NULL | NULL | YES | BTREE | |
| zip_codes | 1 | country_region_city | 2 | country | A | 218424 | NULL | NULL | YES | BTREE | |
| zip_codes | 1 | country_region_city | 3 | region | A | 436849 | NULL | NULL | YES | BTREE | |
+-----------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
Your city_country_region key on world_cities has a NULL cardinality, while a non-NULL one is required for it to be use. Running analyze on it should fix it.
ANALYZE TABLE world_cities
Also have a look at this post for more info on NULL cardinality.

MySQL query optimisation, big table, using temporary filesort

I need your help optimizing a query. One table is a log table which has millions of entries and I try to break my query to < 1s. My query should give an overall overview and should be quick therefore. I'm sure I could make multiple simple queries over the list with help of a script. But what a script can do, can mysql I think - I hope at least. And maybe not all parts are best used, but I'm stuck in a query which makes a temporary table and filesort (which I found out is really bad). As reading around I found out to use some neat and well placed indexes but now I'm stuck in a specific point.
Let me show you my final query with its results:
SELECT
ps.SERVER_ID,
ps.FULLNAME,
SUM(CASE WHEN pml.ID_TYPE = 3 THEN 1 ELSE 0 END) 'amount_warning',
SUM(CASE WHEN pml.ID_TYPE = 4 THEN 1 ELSE 0 END) 'amount_error',
SUM(CASE WHEN pml.ID_TYPE = 5 THEN 1 ELSE 0 END) 'amount_alert',
SUM(CASE WHEN pml.ID_TYPE = 7 THEN 1 ELSE 0 END) 'amount_critical'
FROM
PAR_SERVER ps
INNER JOIN
PAR_MONITORINGv2_LOG pml ON ps.SERVER_ID = pml.SERVER_ID
WHERE
pml.CREATED_DATE > date_sub( NOW( ) , INTERVAL 7 DAY )
GROUP BY
ps.SERVER_ID;
Here is what I get:
mysql> [thequeryabove]
[...]
59 rows in set (11.69 sec)
mysql> explain [thequeryabove]
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+
| 1 | SIMPLE | pml | ALL | SERVER_ID,SERVER_ID-ID_TYPE | NULL | NULL | NULL | 4014447 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | ps | eq_ref | PRIMARY | PRIMARY | 4 | database.pml.SERVER_ID | 1 | |
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+
2 rows in set (0.00 sec)
Here's my current table setup:
mysql> describe PAR_SERVER;
+----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+----------------+
| SERVER_ID | int(255) | NO | PRI | NULL | auto_increment |
| FULLNAME | varchar(255) | YES | | NULL | |
| SHORTNAME | varchar(255) | YES | MUL | NULL | |
+----------------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> show indexes from PAR_SERVER;
+------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| PAR_SERVER | 0 | PRIMARY | 1 | SERVER_ID | A | 142 | NULL | NULL | | BTREE | |
| PAR_SERVER | 1 | shortname | 1 | SHORTNAME | A | 142 | NULL | NULL | YES | BTREE | |
+------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
2 rows in set (0.00 sec)
mysql> select count(*) from PAR_SERVER;
+----------+
| count(*) |
+----------+
| 142 |
+----------+
1 row in set (0.00 sec)
mysql> describe PAR_MONITORINGv2_LOG;
+--------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+----------+------+-----+---------+----------------+
| ID | int(11) | NO | PRI | NULL | auto_increment |
| ID_TYPE | int(11) | NO | MUL | NULL | |
| ID_SERVICE | int(11) | NO | MUL | NULL | |
| SERVER_ID | int(11) | NO | MUL | NULL | |
| MESSAGE | tinytext | NO | | NULL | |
| CREATED_DATE | datetime | NO | | NULL | |
+--------------+----------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
mysql> show indexes from PAR_MONITORINGv2_LOG;
+----------------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| PAR_MONITORINGv2_LOG | 0 | PRIMARY | 1 | ID | A | 3998188 | NULL | NULL | | BTREE | |
| PAR_MONITORINGv2_LOG | 1 | ID_TYPE | 1 | ID_TYPE | A | 7 | NULL | NULL | | BTREE | |
| PAR_MONITORINGv2_LOG | 1 | ID_SERVICE | 1 | ID_SERVICE | A | 5 | NULL | NULL | | BTREE | |
| PAR_MONITORINGv2_LOG | 1 | SERVER_ID | 1 | SERVER_ID | A | 66 | NULL | NULL | | BTREE | |
| PAR_MONITORINGv2_LOG | 1 | SERVER_ID-ID_TYPE | 1 | SERVER_ID | A | 66 | NULL | NULL | | BTREE | |
| PAR_MONITORINGv2_LOG | 1 | SERVER_ID-ID_TYPE | 2 | ID_TYPE | A | 258 | NULL | NULL | | BTREE | |
+----------------------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
6 rows in set (0.00 sec)
mysql> select count(*) from PAR_MONITORINGv2_LOG;
+----------+
| count(*) |
+----------+
| 3998386 |
+----------+
1 row in set (0.00 sec)
Here are time results breaking my query step by step down. I may going step by step up after fixing each part taking so long. But for now only the query with runtime of 2.30 sec is currently interesting for this question.
mysql> SELECT ps.SERVER_ID, ps.FULLNAME FROM PAR_SERVER ps INNER JOIN PAR_MONITORINGv2_LOG pml ON ps.SERVER_ID = pml.SERVER_ID WHERE pml.CREATED_DATE > date_sub( NOW( ) , INTERVAL 7 DAY ) GROUP BY ps.SERVER_ID;
[...]
59 rows in set (6.41 sec)
mysql> explain [thequeryabove]
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+
| 1 | SIMPLE | pml | ALL | SERVER_ID,SERVER_ID-ID_TYPE | NULL | NULL | NULL | 4014788 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | ps | eq_ref | PRIMARY | PRIMARY | 4 | database.pml.SERVER_ID | 1 | |
+----+-------------+-------+--------+-----------------------------+---------+---------+---------------------------+---------+----------------------------------------------+
2 rows in set (0.00 sec)
mysql> SELECT ps.SERVER_ID, ps.FULLNAME FROM PAR_SERVER ps INNER JOIN PAR_MONITORINGv2_LOG pml ON ps.SERVER_ID = pml.SERVER_ID GROUP BY ps.SERVER_ID;
[...]
59 rows in set (2.30 sec)
mysql> explain [thequeryabove]
+----+-------------+-------+--------+-----------------------------+-----------+---------+---------------------------+---------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------------+-----------+---------+---------------------------+---------+----------------------------------------------+
| 1 | SIMPLE | pml | index | SERVER_ID,SERVER_ID-ID_TYPE | SERVER_ID | 4 | NULL | 4015694 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | ps | eq_ref | PRIMARY | PRIMARY | 4 | database.pml.SERVER_ID | 1 | |
+----+-------------+-------+--------+-----------------------------+-----------+---------+---------------------------+---------+----------------------------------------------+
2 rows in set (0.00 sec)
mysql> SELECT pml.SERVER_ID FROM PAR_MONITORINGv2_LOG pml GROUP BY pml.SERVER_ID;
[...]
65 rows in set (0.00 sec)
mysql> explain [thequeryabove]
+----+-------------+-------+-------+---------------+-----------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-----------+---------+------+------+--------------------------+
| 1 | SIMPLE | pml | range | NULL | SERVER_ID | 4 | NULL | 67 | Using index for group-by |
+----+-------------+-------+-------+---------------+-----------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
I was able to improve the query a lot by defining an index for (SERVER_ID, ID_TYPE) as my following example query confirms:
mysql> SELECT count(*) 'count_warnings' FROM PAR_MONITORINGv2_LOG pml WHERE pml.SERVER_ID = 191 AND pml.ID_TYPE = 3 GROUP BY pml.SERVER_ID;
[...]
1 row in set (0.01 sec)
mysql> explain [thequeryabove]
+----+-------------+-------+------+-------------------------------------+-------------------+---------+-------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-------------------------------------+-------------------+---------+-------------+-------+-------------+
| 1 | SIMPLE | pml | ref | ID_TYPE,SERVER_ID,SERVER_ID-ID_TYPE | SERVER_ID-ID_TYPE | 8 | const,const | 10254 | Using index |
+----+-------------+-------+------+-------------------------------------+-------------------+---------+-------------+-------+-------------+
1 row in set (0.00 sec)
I'm stuck now in the most broked down query with a long execution time of 2.30 sec. I don't know how to use indexes for such a query not having any where clause.
Your query will definitely benefit the most from adding composite index on PAR_MONITORINGv2_LOG(CREATED_DATE, SERVER_ID,ID_TYPE). However, I suggest even simple index on CREATED_DATE will improve performance a lot.

Can I optimize this kind of query?

I have this query:
SELECT
s.last_spread, s.sd, s.mean, s.id
,c.id_ticker, c.coef
,t.ticker
,p.last, p.price
FROM (SELECT * FROM spreads WHERE spreads.id_check=1 LIMIT 100,500 ) as s
INNER JOIN coef as c
ON c.id_spread = s.id
INNER JOIN tickers AS t
ON t.id = c.id_ticker
LEFT JOIN (SELECT prices.id_ticker, MAX(prices.date) as last, prices.price FROM prices GROUP BY prices.id_ticker) AS p
ON p.id_ticker = t.id
These are the schemas of the tables:
mysql> desc spreads;
+-------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| id_check | int(11) | YES | MUL | NULL | |
| sd | double | YES | | NULL | |
| mean | double | YES | | NULL | |
| last_spread | double | YES | | NULL | |
+-------------+---------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql> desc coef;
+-----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| id_spread | int(11) | YES | MUL | NULL | |
| id_ticker | int(11) | YES | | NULL | |
| coef | double | YES | | NULL | |
| side | double | YES | | NULL | |
+-----------+---------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql> desc tickers;
+----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| ticker | varchar(45) | NO | | NULL | |
| name | varchar(150) | NO | | NULL | |
| category | varchar(150) | NO | | NULL | |
| issuer | varchar(150) | NO | | NULL | |
+----------+------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql> desc prices;
+-----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| id_ticker | int(10) unsigned | NO | MUL | NULL | |
| date | date | NO | | NULL | |
| price | double | NO | | NULL | |
+-----------+------------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)
These are the indexes of the above tables;
mysql> show indexes from spreads;
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| spreads | 0 | PRIMARY | 1 | id | A | 2299 | NULL | NULL | | BTREE | |
| spreads | 1 | check_idx | 1 | id_check | A | 1 | NULL | NULL | YES | BTREE | |
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
2 rows in set (0.00 sec)
mysql> show indexes from coef;
+-------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| coef | 0 | PRIMARY | 1 | id | A | 9078 | NULL | NULL | | BTREE | |
| coef | 1 | spread_ticker_idx | 1 | id_spread | A | NULL | NULL | NULL | YES | BTREE | |
| coef | 1 | spread_ticker_idx | 2 | id_ticker | A | NULL | NULL | NULL | YES | BTREE | |
+-------+------------+-------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
3 rows in set (0.00 sec)
mysql> show indexes from tickers;
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| tickers | 0 | PRIMARY | 1 | id | A | 100 | NULL | NULL | | BTREE | |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
1 row in set (0.00 sec)
mysql> show indexes from prices;
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| prices | 0 | PRIMARY | 1 | id | A | 19962 | NULL | NULL | | BTREE | |
| prices | 1 | id_ticker | 1 | id_ticker | A | 19962 | NULL | NULL | | BTREE | |
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
2 rows in set (0.15 sec)
And this is the explain of the query:
+----+-------------+------------+--------+-------------------+-------------------+---------+---------------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+-------------------+-------------------+---------+---------------------------+--------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 500 | |
| 1 | PRIMARY | c | ref | spread_ticker_idx | spread_ticker_idx | 5 | s.id | 90 | Using where |
| 1 | PRIMARY | t | eq_ref | PRIMARY | PRIMARY | 4 | spreadtrading.c.id_ticker | 1 | Using where |
| 1 | PRIMARY | <derived3> | ALL | NULL | NULL | NULL | NULL | 100 | |
| 3 | DERIVED | prices | index | NULL | id_ticker | 4 | NULL | 119774 | |
| 2 | DERIVED | spreads | ref | check_idx | check_idx | 5 | | 2298 | Using where |
+----+-------------+------------+--------+-------------------+-------------------+---------+---------------------------+--------+-------------+
6 rows in set (0.27 sec)
Could I optimize it?
Thank you!
EDIT:
I would like to know if the INDEXES and the table's structure are optimized for the query I posted above. The results that I get using this query are good, it works well, but maybe I can optimize it to increse the "speed" of the query.
I think you may gain something by dropping the spreads subquery and moving the WHERE clause to the end, as in the following code. This loses your LIMIT restriction - perhaps you could put a LIMIT clause at the end as well, depending on what you're trying to achieve in terms of limiting the size of the output.
SELECT
s.last_spread, s.sd, s.mean, s.id
,c.id_ticker, c.coef
,t.ticker
,p.last, p.price
FROM spreads as s
INNER JOIN coef as c
ON c.id_spread = s.id
INNER JOIN tickers AS t
ON t.id = c.id_ticker
LEFT JOIN (SELECT prices.id_ticker, MAX(prices.date) as last, prices.price FROM prices GROUP BY prices.id_ticker) AS p
ON p.id_ticker = t.id
WHERE s.id_check = 1