How optimize this query - mysql

select mobile_no,mobile_source_type_id,voter_id,district_id,
constituency_id,tehsil_id,local_election_body_id,panchayat_id,
booth_id,is_dnd
from mobile_numbers2
where mobile_no not in (
SELECT mobile_number
from mobile_numbers
)
For this Query it's taking more time.
By using Explain query . It showing below message, How optimize this query.
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY mobile_numbers2 ALL NULL NULL NULL NULL 7783355 Using where
2 DEPENDENT SUBQUERY mobile_numbers index idx_mobile_numbers_mobile_number,idx_mobile_no idx_mobile_numbers_mobile_number 48 NULL 49256693 Using where; Using index

since I don't have your database at my disposal, I'm unable to test this query so it may need some tweaking, but this might be faster:
select
mobile_no as mobile_no1,
mobile_numbers.mobile_number as mobile_no2,
mobile_source_type_id,
voter_id,
district_id,
constituency_id,
tehsil_id,
local_election_body_id,
panchayat_id,
booth_id,
is_dnd
from mobile_numbers2
left join mobile_numbers on mobile_numbers.mobile_number = mobile_numbers2.mobile_no
where mobile_no2 IS NULL
A couple of notes:
Subqueries, particularly when paired with 'IN()' are slow
if I were maintaining your database, I would create a single 'mobile_numbers' table and I would reference it from all other tables using it's 'id' column, this would make things cleaner/faster in general.

Related

Laravel Join tables and group by sum query too slow

I am using Laravel query builder to get desired results from database. The following query if working perfectly but taking too much time to get results. Can you please help me with this?
select
`amz_ads_sp_campaigns`.*,
SUM(attributedUnitsOrdered7d) as order7d,
SUM(attributedUnitsOrdered30d) as order30d,
SUM(attributedSales7d) as sale7d,
SUM(attributedSales30d) as sale30d,
SUM(impressions) as impressions,
SUM(clicks) as clicks,
SUM(cost) as cost,
SUM(attributedConversions7d) as attributedConversions7d,
SUM(attributedConversions30d) as attributedConversions30d
from
`amz_ads_sp_product_targetings`
inner join `amz_ads_sp_report_product_targetings` on `amz_ads_sp_product_targetings`.`campaignId` = `amz_ads_sp_report_product_targetings`.`campaignId`
inner join `amz_ads_sp_campaigns` on `amz_ads_sp_report_product_targetings`.`campaignId` = `amz_ads_sp_campaigns`.`campaignId`
where
(
`amz_ads_sp_product_targetings`.`user_id` = ?
and `amz_ads_sp_product_targetings`.`profileId` = ?
)
group by
`amz_ads_sp_product_targetings`.`campaignId`
Result of Explain SQL
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE amz_ads_sp_report_product_targetings ALL campaignId NULL NULL NULL 50061 Using temporary; Using filesort
1 SIMPLE amz_ads_sp_campaigns ref campaignId campaignId 8 pr-amz-ppc.amz_ads_sp_report_product_targetings.ca... 1
1 SIMPLE amz_ads_sp_product_targetings ref campaignId campaignId 8 pr-amz-ppc.amz_ads_sp_report_product_targetings.ca... 33 Using where
Your query could benefit from several indices to cover the WHERE clause as well as the join conditions:
CREATE INDEX idx1 ON amz_ads_sp_product_targetings (
user_id, profileId, campaignId);
CREATE INDEX idx2 ON amz_ads_sp_report_product_targetings (
campaignId);
CREATE INDEX idx3 ON amz_ads_sp_campaigns (campaignId);
The first index idx1 covers the entire WHERE clause, which might let MySQL throw away many records on the initial scan of the amz_ads_sp_product_targetings table. It also includes the campaignId column, which is needed for the first join. The second and third indices cover the join columns of each respective table. This might let MySQL do a more rapid lookup during the join process.
Note that selecting amz_ads_sp_campaigns.* is not valid unless the campaignId of that table be the primary key. Also, there isn't much else we can do speed up the query, as SUM, by its nature, requires touching every record in order to come up the result sum.

Why this simple query not using any one index?

Query:
SELECT *, history_count as `count`
FROM pdf_history
WHERE 1 AND history_date>=1426180929 AND history_count!=0
EXPLAIN
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE pdf_history ALL history_date,history_count NULL NULL NULL 697 Using where
One of the reason optimizer choose not to use the index is when the filter doesn't reduce the search space.
for example if
history_date>=1426180929
or
history_count!=0
already bring all the records then using the index doesnt really help.
My suggestion do this both querys and check the ANALYZEto see how many of the
600 records are match that filter
SELECT count(*) FROM pdf_history WHERE history_date>=1426180929;
SELECT count(*) FROM pdf_history WHERE history_count!=0;

How to improve IF NOT NULL query?

I have the following query:
SELECT * FROM `title_mediaasset`
WHERE upload_id is not null
ORDER BY `upload_date` DESC
It takes almost a second and doesn't use an index:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE title_mediaasset ALL upload_id,upload_id_2 NULL NULL NULL 119216 Using where; Using filesort
How can I improve this query?
This table holds about 100k results, and will probably increase to 1M in the next year.
If you need all rows and all columns from the result, you can't re-write the query to make it better. It is probably running slow because you don't have an index on upload_date.
If you don't need all of the rows, use LIMIT and you'll see a decent speed increase on the ORDER BY.
If you don't need all of the columns, use SELECT [columns you need] instead of SELECT *. That way if you really need to optimize the query, you can put the columns you need in your index so that you can read everything directly from the index: index on (upload_id, upload_date, [other columns in select statement]).
If you need all of the columns, or a good number of them, just add index on (upload_id, upload_date).

Optimization of a Virtuemart Attribute Query

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.

Help on MySQL table indexing when GROUP BY is used in a query

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".