I have a really slow query that repeats itself quite a bit. I've tried indexing the individual fields but it doesn't seem to help. The CPU usage is still very high and the queries still appear on the slow query log. It seems I need a compound index?
How would I index the following query properly?
select *
from `to_attachments` left join
`attachments`
on `to_attachments`.`attachment_id` = `attachments`.`id`
where `to_attachments`.`object_type` = 'communicator' and `to_attachments`.`object_id` = '64328'
order by `attachments`.`created_at` desc;
EXPLAIN Result:
1 SIMPLE to_attachments index NULL PRIMARY 775 NULL 244384 Using where; Using index; Using temporary; Using filesort
1 SIMPLE attachments eq_ref PRIMARY PRIMARY 4 quote.to_attachments.attachment_id 1 NULL
Index For to_attachments
You want indexes on to_attachments(object_type, object_id, attachment_id) and attachments(id).
You sequence of the index is wrong it should be (object_type, object_id, attachment_id). In the multicolumn index order of the columns in the index is MATTER.
Related
I have a select query below, what it does is it selects all the products matching a certain attribute from a Virtuemart table. The attribute table is rather large (almost 6000 rows). Is there any way to optimize the query below or are there any other process that might be helpful, I already tried adding indexes to one and even two tables.
SELECT DISTINCT `jos_vm_product`.`product_id`,
`jos_vm_product_attribute`.`attribute_name`,
`jos_vm_product_attribute`.`attribute_value`,
`jos_vm_product_attribute`.`product_id`
FROM (`jos_vm_product`)
RIGHT JOIN `jos_vm_product_attribute`
ON `jos_vm_product`.`product_id` = `jos_vm_product_attribute`.`product_id`
WHERE ((`jos_vm_product_attribute`.`attribute_name` = 'Size')
AND ((`jos_vm_product_attribute`.`attribute_value` = '6.5')
OR (`jos_vm_product_attribute`.`attribute_value` = '10')))
GROUP BY `jos_vm_product`.`product_sku`
ORDER BY CONVERT(`jos_vm_product_attribute`.`attribute_value`, SIGNED INTEGER)
LIMIT 0, 24
Here is the results of the EXPLAIN table:
id select_type table type possible_keys key key_len ref rows Extras
1 SIMPLE jos_vm_product_attribute range idx_product_attribute_name,attribute_value,attribute_name attribute_value 765 NULL 333 Using where; Using temporary; Using filesort
1 SIMPLE jos_vm_product eq_ref PRIMARY PRIMARY 4 shoemark_com_shop.jos_vm_product_attribute.product_id
Any help would be greatly appreciated. Thanks.
Replacing the jos_vm_product_attribute.attribute_name index with a composite index on jos_vm_product_attribute.attribute_name and jos_vm_product_attribute.attribute_value (in that order) should help this query. Currently, it's only using an index in the WHERE condition for jos_vm_product_attribute.attribute_value, but this new index will be usable for both parts of the WHERE condition.
I have a database with a bunch of records and when I load up the page with the following SQL its really slow.
SELECT goal.title, max(updates.date_updated) as update_sort
FROM `goal`
LEFT OUTER JOIN `update` `updates` ON (`updates`.`goal_id`=`goal`.`goal_id`)
WHERE (goal.private=0)
GROUP BY updates.goal_id
ORDER BY update_sort desc
LIMIT 12
When I do an explain it says its not using any keys and that its searching every row. Also telling me its using "Using where; Using temporary; Using filesort".
Any help is much appreciated
Thanks
It needs to be grouped by goal_id because of the MAX() in the select is returning only one row.
What i'm trying to do is return the MAX date_updated row from the updates table for each goal and then sort it by that column.
Current indices are on goal.private and update.goal_id
output of EXPLAIN (can't upload images so have to put it here sorry if it isnt clear:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE goal ref private private 1 const 27 Using temporary; Using filesort
1 SIMPLE updates ref goal_id goal_id 4 goal.goal_id 1
SELECT u.date_updated, g.title
FROM updates u
JOIN goal g
ON g.goal_id = u.goal_id
WHERE u.id =
(
SELECT ui.id
FROM updates ui
WHERE ui.goal_id = u.goal_id
ORDER BY
ui.goal_id, ui.date_updated, ui.id
LIMIT 1
)
AND g.private = 0
ORDER BY
u.date_update, u.id
LIMIT 12
Create two indexes on updates for the query to work fast:
updates (goal_id, date_updated, id)
updates (date_updated, id)
My guess is that the MAX() function causes this behaviour. It needs to look at every record to decide what rows to select. What kind of grouping are you trying to accomplish?
I have a database with the following info:
table reports: 166211 records
table report_content: 166211 records
table companies: 13188 records
This query takes 41.7324 sec to process:
select rc.* from `reports` r
left join `report_content` rc on rc.`report`=r.`id`
left join `companies` c on c.`id`=r.`company`
where not isnull(r.`published`) and not r.`deleted`
order by rc.`company` asc
limit 50
Where as this query takes 1.6146 sec to process:
I added and rc.company != ''
select rc.* from `reports` r
left join `report_content` rc on rc.`report`=r.`id`
left join `companies` c on c.`id`=r.`company`
where not isnull(r.`published`) and not r.`deleted`
and rc.`company` != ''
order by rc.`company` asc
limit 50
I have fulltext index on rc.company with a cardinality of 11872
all other clause/join fields have btree indexes (mostly primary)
Why is this so? Should i be using a fulltext/btree index on a varchar(255)?
The idea is to not have the rc.company != ''
FYI, the tables are MyISAM
note: The added condition doesn't change the result, it's merely to add rc.company into the conditions (this speeds up the query) and wonder if it is elegant?
Update: Thanks Frail, here are the results:
Query A:
1 SIMPLE r range published published 9 NULL 156085 Using where; Using temporary; Using filesort
1 SIMPLE rc ref report report 4 database.r.id 1
1 SIMPLE c eq_ref PRIMARY PRIMARY 4 database.r.company 1 Using index
Query B:
1 SIMPLE rc ALL report,company NULL NULL NULL 166339 Using where; Using filesort
1 SIMPLE r eq_ref PRIMARY,published PRIMARY 4 database.rc.report 1 Using where
1 SIMPLE c eq_ref PRIMARY PRIMARY 4 database.r.company 1 Using index
As far as I know full-text index is not for sorting. and you are sorting the result with the company column.
Let me try to explain full-text for you simply:
id company
1 "brown fox"
2 "something of fox"
your full-text index would create a btree for the words : "brown, something, fox" so you can match against these words, but as far as I know it wont help you sort.
so if you are using full-text index to get "fox" companies, keep it. but put a btree index on company aswell for sorting purposes.
You haven't listed your table indexes but try creating the following 3 indexes
on the reports table (published,deleted,company,id)
on the report_content table (report,company)
on the companies table (id)
Thank you for your attention.
There are two INNODB tables:
Table authors
id INT
nickname VARCHAR(50)
status ENUM('active', 'blocked')
about TEXT
Table books
author_id INT
title VARCHAR(150)
I'm running a query against these tables, to get each author and a count of books he has:
SELECT a. * , COUNT( b.id ) AS book_count
FROM authors AS a, books AS b
WHERE a.status != 'blocked'
AND b.author_id = a.id
GROUP BY a.id
ORDER BY a.nickname
This query is very slow (takes about 6 seconds to execute). I have an index on books.author_id and it works perfectly, but I do not know how to create an index on authors table, so that this query could use it.
Here is how current EXPLAIN looks:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE a ALL PRIMARY,id_status_nickname NULL NULL NULL 3305 Using where; Using temporary; Using filesort
1 SIMPLE b ref key_author_id key_author_id 5 a.id 2 Using where; Using index
I've looked at MySQL manual on optimizing queries with group by, but could not figure out how I can apply it on my query.
I'll appreciate any help and hints on this - what must be the index structure, so that MySQL could use it?
Edit
I have tried:
(id, status, nickname)
(status, nickname)
Both resulted in the same situation.
I assume that the id_status_nickname is a composite index (id,status,nickname). In your query you filter the rows by saying a.status != blocked. This has following issues:
You dont have an index that can be used for this. (id,status,nickname) cannot be used because status is not the prefix of that index
Assuming you have an index on status, it cannot be used when using !=. you have to change that to status='active'
Also, status being an enum field with just two values the cardinality will be low. So mysql may endup not using the index at all.
You can try this: create index as (status,id,nickname) and use status='active'. My guess is that since you are using '=' and status is the prefix of the index it should select this index and then use it for group by and then order by.Hope this helps.
UPDATE:
Looks like it is not possible to avoid filesort when the WHERE clause does not have the field used in ORDER BY.
I would try an index on (status, nickname). That should get rid of the necessity of "Using filesort".
I've got a trivial mysql query which isn't liked by the server really:
SELECT zone_id, SUM(inc_sec) AS voucher_used
FROM cdr_bill_2010_09
WHERE cust_id = 1234 AND voucher_id = 'XXXXXX'
GROUP BY zone_id
Now this should be really quick (and usually is) since there are indexes on both cust_id and voucher_id (voucher_id is chosen). However it still uses helper tables. After explaining:
id: 1
select_type: SIMPLE
table: cdr_bill_2010_09
type: ref
possible_keys: cust_id,voucher_id
key: voucher_id
key_len: 9
ref: const
rows: 1
Extra: Using where; Using temporary; Using filesort
Can I do something specific to get rid of those? I'm running debian's 5.0.45.
just try to add another index (according to http://forums.mysql.com/read.php?115,57443,59562):
CREATE INDEX index_zi ON cdr_bill_2010_09 (zone_id,inc_sec);
Are you indexing all the bytes in the voucher_id?
from http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html :
You index only a prefix of a column
named in the ORDER BY clause. In this
case, the index cannot be used to
fully resolve the sort order. For
example, if you have a CHAR(20)
column, but index only the first 10
bytes, the index cannot distinguish
values past the 10th byte and a
filesort will be needed.
I know it's not an order by clause, but maybe the same deal?
Have you tried creating an index with both cust_id and vendor_id in it?
create index idx_cdr_bill_2010_09_joint on cdr_bill_2010_09(cust_id, vendor_id)
The actual answer was close to the other ones. Adding an index with both "where" key (voucher_id) or (cust_id) and the "group" key (zone_id) fixed the problem. Actually zone_id itself was sufficient to get rid of additional temporary / filesort, but adding another one was needed to use the speed up the basic query.
CREATE INDEX IDX_CDRBILL_CUST_VOUCH_ZONE ON cdr_bill_2010_09 (cust_id,
voucher_id, zone_id);