Question

This question follows on from the problem posted here when i run explain I on my query

SELECT u_id, SUM(counts.s_count * tablename.weighted) AS total FROM tablename 
LEFT JOIN (SELECT a_id, s_count FROM tablename WHERE u_id = 1) counts
  ON tablename.a_id = counts.a_id
GROUP BY u_id ORDER BY total DESC LIMIT 0,100;

I get the response

+----+-------------+--------------------+-------+---------------+-----------+---------+------+--------+----------------------------------------------+
| id | select_type | table              | type  | possible_keys | key       | key_len | ref  | rows   | Extra                                        |
+----+-------------+--------------------+-------+---------------+-----------+---------+------+--------+----------------------------------------------+
|  1 | PRIMARY     | tablename          | index | NULL          | a_id      | 3       | NULL | 7222350| Using index; Using temporary; Using filesort |
|  1 | PRIMARY     | [derived2]         | ALL   | NULL          | NULL      | NULL    | NULL |    37  |                                              |
|  2 | DERIVED     | tablename          | ref   | PRIMARY       | PRIMARY   | 4       |      |    37  | Using index                                  |
+----+-------------+--------------------+-------+---------------+-----------+---------+------+-------+----------------------------------------------+

the table is created with

CREATE TABLE IF NOT EXISTS tablename (
  u_id INT NOT NULL,
  a_id MEDIUMINT NOT NULL,
  s_count MEDIUMINT NOT NULL,
  weighted FLOAT NOT NULL,
  INDEX (a_id),
  PRIMARY KEY (u_id,a_id)
)ENGINE=INNODB;

how can I change the index or query to get it to make use of the key more effectively? Once the database grows to a 7 million rows the query takes about 30 seconds

edit
which can be created with dummy data using

CREATE TABLE IF NOT EXISTS tablename ( u_id INT NOT NULL,   a_id MEDIUMINT NOT NULL,s_count MEDIUMINT NOT NULL,  weighted FLOAT NOT NULL,INDEX (a_id), PRIMARY KEY (u_id,a_id))ENGINE=INNODB;
INSERT INTO tablename (u_id,a_id,s_count,weighted ) VALUES (1,1,17,0.0521472392638),(1,2,80,0.245398773006),(1,3,2,0.00613496932515),(1,4,1,0.00306748466258),(1,5,1,0.00306748466258),(1,6,20,0.0613496932515),(1,7,3,0.00920245398773),(1,8,100,0.306748466258),(1,9,100,0.306748466258),(1,10,2,0.00613496932515),(2,1,1,0.00327868852459),(2,2,1,0.00327868852459),(2,3,100,0.327868852459),(2,4,200,0.655737704918),(2,5,1,0.00327868852459),(2,6,1,0.00327868852459),(2,7,0,0.0),(2,8,0,0.0),(2,9,0,0.0),(2,10,1,0.00327868852459),(3,1,15,0.172413793103),(3,2,40,0.459770114943),(3,3,0,0.0),(3,4,0,0.0),(3,5,0,0.0),(3,6,10,0.114942528736),(3,7,1,0.0114942528736),(3,8,20,0.229885057471),(3,9,0,0.0),(3,10,1,0.0114942528736);
Was it helpful?

Solution

You can hardly force MySQL to use an index for the join with results of a subquery, but you can try to speed up the grouping by using a coverage index (an index that has enough data not to fetch the row it references):

Try to add an composite index (u_id, a_id, weighted)

And you will probably need to give MySQL a hint to use the index:

SELECT u_id, SUM(counts.s_count * tablename.weighted) AS total
FROM tablename USE INDEX(Index_3)
LEFT JOIN (SELECT a_id, s_count FROM tablename WHERE u_id = 1) counts
  ON tablename.a_id = counts.a_id
GROUP BY u_id ORDER BY total DESC LIMIT 0,100;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top