简体   繁体   中英

Trying To Find The Cause Of Very Slow LEFT JOIN MySQL Query

I would appreciate any help trying to find the cause of very slow return times on basic query table joins.

I was having trouble so I turned on Profiling and Query that took 19.7903 sec to return showed the following profile details:

Profiling
Status  Time
starting    0.000044
Opening tables  0.000067
System lock     0.000002
Table lock  0.000006
init    0.000009
optimizing  0.000005
statistics  0.000011
preparing   0.000014
executing   0.000031
Sending data    0.000050
end     0.000004
end     0.000003
query end   0.000002
freeing items   0.000009
closing tables  0.000003
removing tmp table  0.000011
closing tables  0.000003
logging slow query  0.000002
cleaning up     0.000003

Showing rows 0 - 29 (2,200 total, Query took 19.7903 sec)

I don't understand why the profile times do not add up to "19.7903 sec".

  • Are the 'profile' time and the 'total, Query' time, to add up? <<<<<<<

The query was:

SELECT OWNER.ID                                         OWNER_ID,
       OWNER.LAST_NAME                                  OWNER_LAST_NAME,
       OWNER.FIRST_NAME                                 OWNER_FIRST_NAME,
       OWNER.PHONE_HOME_AREACODE                        OWNER_PHONE_HOME_AREACODE,
       OWNER.PHONE_HOME_PREFIX                          OWNER_PHONE_HOME_PREFIX,
       OWNER.PHONE_HOME_LINE_NUMBER                     OWNER_PHONE_HOME_LINE_NUMBER,
       OWNER.PHONE_CELL_AREACODE                        OWNER_PHONE_CELL_AREACODE,
       OWNER.PHONE_CELL_PREFIX                          OWNER_PHONE_CELL_PREFIX,
       OWNER.PHONE_CELL_LINE_NUMBER                     OWNER_PHONE_CELL_LINE_NUMBER,
       /*Some columns from OWNER removed for brevity*/
       OWNER.CITY                                       OWNER_CITY,
       OWNER.PROVINCE                                   OWNER_PROVINCE,
       OWNER.POSTAL                                     OWNER_POSTAL,
       OWNER.NOTES                                      OWNER_NOTES,
       OWNER.REFERRED_BY                                OWNER_REFERRED_BY,
       VISITOR.NAME                                     VISITOR_NAME,
       VISITOR.SIZE                                     VISITOR_SIZE,
       VISITOR.INACTIVE                                 VISITOR_INACTIVE,
       VISITOR.ID                                       VISITOR_ID,
       VISITOR.DELETED                                  VISITOR_DELETED,
       VACCINATIONS.CANINE_DISTEMPER_PARVOVIRUS_EXPIRES VACCINATIONS_CANINE_DISTEMPER_PARVOVIRUS_EXPIRES,
       VACCINATIONS.CANINE_RABIES_EXPIRES               VACCINATIONS_CANINE_RABIES_EXPIRES,
       VACCINATIONS.CANINE_BORDETELLA_EXPIRES           VACCINATIONS_CANINE_BORDETELLA_EXPIRES,
       VACCINATIONS.FELINE_FVRCPC_EXPIRES               VACCINATIONS_FELINE_FVRCPC_EXPIRES,
       VACCINATIONS.FELINE_RABIES_EXPIRES               VACCINATIONS_FELINE_RABIES_EXPIRES
FROM   OWNER
       LEFT JOIN VISITOR
         ON VISITOR.OWNER_ID = OWNER.ID
       LEFT JOIN VACCINATIONS
         ON VACCINATIONS.VISITOR_ID = VISITOR.ID
ORDER  BY VISITOR_NAME 

Result of EXPLAIN:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  OWNER   ALL     NULL    NULL    NULL    NULL    1483    Using temporary; Using filesort
1   SIMPLE  VISITOR     ref     OWNER_ID    OWNER_ID    4   wayDEV.OWNER.ID     1    
1   SIMPLE  VACCINATIONS    ALL     VISITOR_ID  NULL    NULL    NULL    2059     

INDEXES:

VISITOR:
Indexes: Documentation Keyname  Type    Cardinality     Action  Field
PRIMARY     PRIMARY     2227    Edit    Drop    ID
NAME    INDEX   2227    Edit    Drop    NAME
OWNER_ID    INDEX   2227    Edit    Drop    OWNER_ID 


OWNER:
Indexes: Documentation Keyname  Type    Cardinality     Action  Field
PRIMARY     PRIMARY     1601    Edit    Drop    ID
LAST_NAME   INDEX   1601    Edit    Drop    LAST_NAME 

VACCINATIONS:
Indexes: Documentation Keyname  Type    Cardinality     Action  Field
PRIMARY     PRIMARY     2131    Edit    Drop    ID
VISITOR_ID  UNIQUE  2131    Edit    Drop    VISITOR_ID 

BOARDING:
Indexes: Documentation Keyname  Type    Cardinality     Action  Field
PRIMARY     PRIMARY     2256    Edit    Drop    ID
OWNER   INDEX   2256    Edit    Drop    OWNER_ID
VISITOR     INDEX   2256    Edit    Drop    VISITOR_ID 

GROOMING:
Indexes: Documentation Keyname  Type    Cardinality     Action  Field
PRIMARY     PRIMARY     2077    Edit    Drop    ID
VISITOR_ID  UNIQUE  2077    Edit    Drop    VISITOR_ID
OWNER   INDEX   2077    Edit    Drop    OWNER_ID 

This query has performed fine for months. It is only recently and only intermittently that it comes back slow. About 20% of the time it will be slow. The rest of the time it returns just fine ( Showing rows 0 - 29 (2,200 total, Query took 0.0018 sec )). ? :\\

  • Could the fact that it is an intermittent problem indicate some problem other that the Query itself?? <<<<<<<

    As I ask above... I don't understand why the profile times do not add up to "19.7903 sec".

  • Are the 'profile' time and the 'total, Query' time, to add up? <<<<<<<


Only a few thousand records in the entire database.

Any help would be appreciated. I'm on a Godaddy server.

(I understand that there could potentially be something wrong with my Query.. Or that it could be optimized. But I am asking some pretty specific questions here - noted by the... "<<<<<<<")

Honestly... We are talking about >>>>>>>20<<<<<<< seconds here! Surely this query on a 2000 record database should not be coming back 20 seconds???

The problem is that you order by a field from the second table in the LEFT JOIN. That is no index can actually be effifiently used for ordering, thus MySQL orders the rows with that whole lots of data in each row. The usual solution in MySQL to the query like this is to select only ids and do ordering within a subquery and then back join to the rest of the colums. This is especially the case when you do some paginagion as well (LIMIT shoul also be within the subquery).

You would need a composite covering index (owner_id, name) on VISITOR, and (visitor_id) on VACCINATIONS.

Now rewrite the query as following:

SELECT ...
FROM (
    SELECT o.ID as o_ID, v.ID as v_ID
    FROM OWNER o
    LEFT JOIN VISITOR v ON o.ID = v.OWNER_ID
    ORDER BY v.NAME
) ids
JOIN OWNER o ON o.ID = ids.o_ID
LEFT JOIN VISITOR v ON v.ID = ids.v_ID
LEFT JOIN VACCINATIONS v2 ON v2.VISITOR_ID = v.ID;

DATA TYPES FOR COLUMNS WERE NOT THE SAME - ie

OWNER.ID - DATA TYPE = (int7)
VISITOR.OWNER_ID - DATA TYPE = (int7)
VACCINATIONS.VISITOR_ID  - DATA TYPE = (varchar7)

Setting the data type - for VACCINATIONS.VISITOR_ID - (int7) , resolved the slowness - this table join on over 5000 records, is now as fast as any other MySQL call.

Thanks "GURU" http://forums.phpfreaks.com/topic/173475-left-join-extremely-slow-any-way-to-remedy-16000-lines/

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