简体   繁体   中英

MySQL performance issue in select query with join and group by clause

I am facing performance issue when querying a table with approx 700,000 records. The query takes more than 10 seconds execute for the first time for a specific item_id, if I change the item_id value in the query the query takes nearly the same amount of time to execute. However, subsequent query for the same item_id is fast unless the server is restarted.

The query I am trying to execute is -

select SQL_NO_CACHE item_id, item_rate_id, invoice_type, sum(qty_computed) as qty
from transaction_item 
left join transaction_customer
       on transaction_item.invoice_id = transaction_customer.invoice_id 
where item_id = 17179
group by item_rate_id, invoice_type

My table (InnoDB) structure is -

Table: transaction_item (No primary Key, INDEX: item_id, Contains approx 700,000 rows)

在此处输入图片说明

Table transaction_customer (Primary Key: invoice_id, contains approx 100,000 rows) 在此处输入图片说明

Running explain on the above query gives the following output:

在此处输入图片说明

my.ini config

[mysqld]
query_cache_size=0
query_cache_type=0
innodb_buffer_pool_size = 1G

Any help on fine tuning MySQL config/db schema will be highly appreciated.

Your indexing isn't too bad for the query you have described. What is harming your performance is both of these tables have a significant amount of data in each row. The query needs elements from each table that isn't in the secondary index and therefore large chunks for the table relevant to the specified item need to be in the innodb buffer pool. I haven't looked at the exact numbers however 1G doesn't seem to be enough and your descriptions of the query becoming quicker the second time seem to support this (especially with SQL_NO_CACHE and the query cache disabled (good that its disabled).

Recommendation 1: Increase the innodb_buffer_pool size. Look at SHOW GLOBAL STATUS LIKE 'innodb_buffer_pool%' and look at the number of items purged from the buffer between queries.

If you are really stuck with the RAM available, and following the theme of @Drapp recommendations on indexes, will allow for a innodb buffer pool to be used with only indexes rather than the complete table. This innodb_buffer_pool is being competed against by other queries so the following have limited global impact.

Recommendation 2: (if #1 cannot be done)

ALTER TABLE transaction_item
DROP INDEX item_id
ADD INDEX item_id (item_id, item_rate_id, qty_computed );

ALTER TABLE transaction_customer
ADD INDEX id_type (invoice_id, invoice_type);

Note: Removed sorting, was necessary for GROUP BY . Thanks Rick

Formatted query for readability, but also added aliasing so someone in the future does not have to guess which columns come from which table.

Anyhow, to help optimize the query, you need a composite index to help the where, join and order by.

I would create an index on your Transaction_Item table on (item_id, item_rate_id, invoice_id )

Also, on your Transaction_Customer table, have an index on (Invoice_id, Invoice_Type )

select SQL_NO_CACHE 
        ti.item_id, 
        ti.item_rate_id, 
        tc.invoice_type, 
        sum(ti.qty_computed) as qty
    from 
        transaction_item ti
            left join transaction_customer tc
                on ti.invoice_id = tc.invoice_id 
    where 
        ti.item_id = 17179
    group by 
        ti.item_rate_id, 
        tc.invoice_type

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