Rows_sent: 12 Rows_examined: 549024 - how to optimize mySQL query?

倖福魔咒の 提交于 2020-01-24 15:41:25

问题


I have a database with listings on quite a good server (Quad Core Xeon 2.0Ghz, 16GB RAM, SSD Drives). The database has about 180,000 listings. There's no traffic yet on the server and I'm just testing it with a lot of listings to ensure there are no problems later on when there's actually that many live listings and actual traffic.

But even with no traffic yet, I feel like they should return faster than they actually are.

From the slow queries log, I was able to find this:

# Query_time: 1.575742  Lock_time: 0.000113 Rows_sent: 12  Rows_examined: 549024

There are 180,000 records, it has to return only 12 but it examines over 500,000 and it takes over 1.5 seconds? Something has to be wrong, right? :(

The actual query is:

SELECT a.listing_id, a.name, a.item_price, a.max, a.nb, a.currency,
     a.end_time, a.closed, a.bold, a.hl, a.buy_price, a.is_offer, a.reserve,
     a.owner_id, a.postage_amount, a.fb_current_bid, a.type, a.start_time,
     a.is_relisted_item, a.enable
     FROM db_listings a
     LEFT JOIN db_users u ON u.user_id=a.owner_id  WHERE a.active=1 AND
     a.approved=1 AND a.deleted=0 AND a.creation_in_progress=0 AND
     a.closed=0 AND (a.list_in='store' OR u.shop_active='1')
     GROUP BY a.listing_id
     ORDER BY a.list_in ASC, a.end_time ASC  LIMIT 0, 12;

Indexes are already set on listing_id in db_listings as well as on user_id in db_users. I don't think the db_users join is a problem, because there are only 2 users in there right now.

If you need any additional information to tackle this problem, just let me know.

Any help is greatly appreciated :)


回答1:


First off, there is a problem with your query. You use LEFT JOIN, but you turn into into an implicit INNER JOIN with your where clause: AND (a.list_in='store' OR u.shop_active='1')

Why does this turn the LEFT JOIN into an implicit INNER? Because the LEFT JOIN will produce NULL values for u.shop_active when there is no matching user, but NULL will NEVER equal '1'. This turns the query into an INNER JOIN because any rows produced by the OUTER JOIN will be filtered by the WHERE condition.

This filter is also the reason for the performance problem. You have an OR condition between columns in two different tables. There is no index that can satisfy such a condition.

Here is another way which may perform better. This version will only search for listings where (a.list_in != 'store' and u.shop_active = '1') when there are less than 12 list_in='store' listings.

To use the following, make sure you have an index on (list_in, end_time)

SELECT * FROM
(
    SELECT a.listing_id, a.name, a.item_price, a.max, a.nb, a.currency,
           a.end_time, a.closed, a.bold, a.hl, a.buy_price, a.is_offer, a.reserve,
           a.owner_id, a.postage_amount, a.fb_current_bid, a.type, a.start_time,
           a.is_relisted_item, a.enable
     FROM db_listings a
    WHERE list_in = 'store'
     a.active=1 AND
     a.approved=1 AND 
     a.deleted=0 AND 
     a.creation_in_progress=0 AND
     a.closed=0
    ORDER BY end_time 
    LIMIT 12 
    )
    UNION ALL
    (
        SELECT a.listing_id, a.name, a.item_price, a.max, a.nb, a.currency,
           a.end_time, a.closed, a.bold, a.hl, a.buy_price, a.is_offer, a.reserve,
           a.owner_id, a.postage_amount, a.fb_current_bid, a.type, a.start_time,
           a.is_relisted_item, a.enable
        FROM db_listings a
        JOIN users u 
          ON a.owner_id = u.user_id
         AND u.shop_active = '1'
       WHERE list_in != 'store' AND
       a.active=1 AND
       a.approved=1 AND 
       a.deleted=0 AND 
       a.creation_in_progress=0 AND
       a.closed=0
       ORDER BY end_time 
       LIMIT 12 
    )
) sq
ORDER BY list_in, end_time
LIMIT 12;


来源:https://stackoverflow.com/questions/11812785/rows-sent-12-rows-examined-549024-how-to-optimize-mysql-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!