Amit
Amit

Reputation: 181

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)

enter image description here

Table transaction_customer (Primary Key: invoice_id, contains approx 100,000 rows) enter image description here

Running explain on the above query gives the following output:

enter image description here

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.

Upvotes: 1

Views: 130

Answers (2)

danblack
danblack

Reputation: 14666

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

Upvotes: 1

DRapp
DRapp

Reputation: 48139

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

Upvotes: 0

Related Questions