简体   繁体   中英

Making a Limit X,Y MySQL Query with Joins Run Faster

I have a MySQL query with a particular structure that I want to rewrite so that it runs faster. It currently runs very slow taking about 255 seconds to execute. If I remove the join it runs in < 10 seconds. Its purpose is to get records from table A, 100 rows at a time, for as long as a user wants to see more rows.

I suspect that the query is taking a long time because it's doing the join on more than just the first 100 rows it finds. Is this true, and if so, is there a way to rewrite the query to do the joining after it gets the rows from the main table?

The data comes from a 'main' table A which has a datetime field (START_TIME) and several foreign keys to tables with string values (tables, B,C,D).

Table A has 2.5 million rows. Table B has 600K rows. Table A has an index on START_TIME. Table B has an index on its ID value.

Here's a basic form of the query. I do not want to put an upper limit on START_TIME because I ALWAYS want to get 100 records back from the query. I use a response which has less than 100 records to indicate that there`s no more records in the database.

SELECT 
    A.START_TIME, A.F1, A.F2, B.STRING
FROM 
    A
     INNER JOIN B ON A.B_ID = B.ID
WHERE
    A.START_TIME >= '2015-03-22 05:23:44'
LIMIT 0, 100;

Here`s the EXPLAIN. Sorry for the format:

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
1, SIMPLE, B, index, PRIMARY, FSN, 95, , 1, Using index; Using temporary; Using filesort
1, SIMPLE, A, ref, A_ix_B_ID,A_ix_C, A_ix_B_ID, 4, ag100_a$$burnaby.B.ID, 2, Using where

You have to provide explain plan so we can help you better.

https://dev.mysql.com/doc/refman/5.5/en/execution-plan-information.html

But for your description you still need index.

TableA beside START_TIME need index for each join field B_id, C_id and D_id and maybe using a composite index for all 4 variable would be better

 CREATE INDEX A_Bid_idx ON A (B_id);
 CREATE INDEX A_Cid_idx ON A (C_id);
 CREATE INDEX A_Did_idx ON A (D_id);

 OR

 CREATE INDEX A_Full_idx ON A (B_id,C_id, D_id, START_TIME);

Table C and D also need index for C.ID and D.ID . And would be even better if they use a composite index

  (C.ID, C.STRING)  and
  (D.ID, D.STRING)

  CREATE INDEX C_id_idx ON C (ID);
  CREATE INDEX D_id_idx ON D (ID);

  OR

  CREATE INDEX C_id_string_idx ON C (ID, STRING);
  CREATE INDEX D_id_string_idx ON C (ID, STRING);

That way db doesnt have to make a lookup to find the string value asociated to the ID

SELECT  A.START_TIME, A.F1, A.F2, 
      ( SELECT  STRING
            FROM  B
            WHERE  A.B_ID = B.ID 
      ) AS String
    FROM  A
    WHERE  A.START_TIME >= '2015-03-22 05:23:44'
    ORDER BY START_TIME
    LIMIT  0, 100; 

will probably run faster. It is 'forced' to use INDEX(START_TIME) from A .

Please provide SHOW CREATE TABLE for both tables; I want to check the datatypes, etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM