Query is running too slow? - mysql

I am writing a MySQL query with left join it giving me result in 28 seconds when I remove and condition with left join then it working in one second can any one tell me what is the issue in my query and how it will be modified?
select *
FROM regist_queue rq
left join appoint ap
on rq.token_number = ap.daily_ticket_no
and rq.LocationId = 15800
and ap.LocationId = 15800
and date(rq.QueueDate) = CURRENT_DATE()
and date(ap.dAppDate) = date(now())
left join patient pr
on ap.iPatID = pr.IPatID
left join gender ge
on pr.vGender = ge.iGenderID
where ifnull(ap.isDel,0) = 0
and ifnull(ap.is_referred,0) != 1
and (ap.LocationId = 15800 or rq.LocationId = 15800 )
order by rq.token_number asc;
I also applied indexes on all searched parameters and where joins are applied.
Explain plan of query.
MySQL Query Plan:

Your purpose is not pretty clear to me. For an example in the join and rq.LocationId = 15800
and ap.LocationId = 15800
and in the where clause and (ap.LocationId = 15800 or rq.LocationId = 15800 )
what my suggestion is to have something like this.
in the left join rq.LocationId = ap.LocationId
and in the where clause ap.LocationId = 15800
it is hard to evaluate the performance without having the real data.

Use SQL with (nolock) in sql query
like :
select *
FROM regist_queue rq with (nolock)
left join appoint ap with (nolock)
on rq.token_number = ap.daily_ticket_no
and rq.LocationId = 15800
and ap.LocationId = 15800
and date(rq.QueueDate) = CURRENT_DATE()
and date(ap.dAppDate) = date(now())
left join patient pr with (nolock)
on ap.iPatID = pr.IPatID
left join gender ge with (nolock)
on pr.vGender = ge.iGenderID
where ifnull(ap.isDel,0) = 0
and ifnull(ap.is_referred,0) != 1
and (ap.LocationId = 15800 or rq.LocationId = 15800 )
order by rq.token_number asc;

it seems there is Cartesian join....
base on the three predicate starts with on .........,
i think the sql statement does not based on your real purpose...

Related

How to optimize performance of count query in symfony doctrine (mysql)?

I used to below query to count rows (~ 1M record and left join many table) :
SELECT COUNT(DISTINCT u0_.id) AS sclr_0
FROM user u0_
LEFT JOIN user_detail u1_ ON u0_.id = u1_.user_id
LEFT JOIN recruitment_info r2_ ON u0_.id = r2_.user_id
LEFT JOIN user u3_ ON u0_.master_account_id = u3_.id
LEFT JOIN applicants_partners a4_ ON u0_.id = a4_.applicant_id
LEFT JOIN partner p5_ ON a4_.partner_id = p5_.id
WHERE u0_.type <> 'PARTNER'
AND u0_.is_delete = 0
ORDER BY u0_.id DESC;
In my symfony, i got total :
$total = $queryBuilder->getQuery()->getSingleScalarResult();
It worked well but it took ~ 2.5s.
So, I would like to improve performance of it. I changed it into :
SELECT COUNT(u0_.id) AS sclr_0
FROM user u0_
LEFT JOIN user_detail u1_ ON u0_.id = u1_.user_id
LEFT JOIN recruitment_info r2_ ON u0_.id = r2_.user_id
LEFT JOIN user u3_ ON u0_.master_account_id = u3_.id
LEFT JOIN applicants_partners a4_ ON u0_.id = a4_.applicant_id
LEFT JOIN partner p5_ ON a4_.partner_id = p5_.id
WHERE u0_.type <> 'PARTNER'
AND u0_.is_delete = 0
GROUP BY u0_.id
ORDER BY u0_.id DESC;
The change here is remove DISTINCT and add GROUP BY.
Then I apply in symfony by count array result:
$result = $queryBuilder->getQuery()->getArrayResult();
$total = count($result);
So the total is correct but this time, it took ~ 20s , OMG. When I tried run only raw query in Sequel Pro tool, it only took ~ 40ms. Maybe there is a problem in getArrayResult() ? . Please help me, thank you.
As Akina mentions it in his comment, you can simplify this query by removing all the left join, the order by and even the distinct.
Your query will become something like this :
SELECT COUNT(u0_.id) AS sclr_0
FROM user u0_
WHERE u0_.type <> 'PARTNER'
AND u0_.is_delete = 0;
And yes, you have to use getSingleScalarResult() on your Doctrine Query instance.

How to show the repeated value as NULL in sql?

I have a query which gives result as below, how to replace duplicate values with NULL
Query:
SELECT
word.lemma,
synset.definition,
synset.pos,
sampletable.sample
FROM
word
LEFT JOIN
sense ON word.wordid = sense.wordid
LEFT JOIN
synset ON sense.synsetid = synset.synsetid
LEFT JOIN
sampletable ON synset.synsetid = sampletable.synsetid
WHERE
word.lemma = 'good'
Result:
Required Result: all the greyed out results as NULL
First, this is the type of transformation that is generally better done at the application level. The reason is that it presupposes that the result set is in a particular order -- and you seem to be assuming this even with no order by clause.
Second, it is often simpler in the application.
However, in MySQL 8+, it is not that hard. You can do:
SELECT w.lemma,
(CASE WHEN ROW_NUMBER() OVER (PARTITION BY w.lemma, ss.definition ORDER BY st.sample) = 1
THEN ss.definition
END) as definition,
ss.pos,
st.sample
FROM word w LEFT JOIN
sense s
ON w.wordid = s.wordid LEFT JOIN
synset ss
ON s.synsetid = ss.synsetid LEFT JOIN
sampletable st
ON ss.synsetid = st.synsetid
WHERE w.lemma = 'good'
ORDER BY w.lemma, ss.definition, st.sample;
For this to work reliably, the outer ORDER BY clause needs to be compatible with the ORDER BY for the window function.
If you are using Mysql 8 try with Rank().. As I didn't have your table or data couldn't test this query.
SELECT
word.lemma
,case when r = 1 synset.definition else null end as definition
,synset.pos
,sampletable.sample
FROM
(
SELECT
word.lemma
,synset.definition
,synset.pos
,sampletable.sample
,RANK() OVER (PARTITION BY synset.definition ORDER BY synset.definition) r
FROM
(
SELECT
word.lemma,
synset.definition,
synset.pos,
sampletable.sample
FROM
word
LEFT JOIN
sense ON word.wordid = sense.wordid
LEFT JOIN
synset ON sense.synsetid = synset.synsetid
LEFT JOIN
sampletable ON synset.synsetid = sampletable.synsetid
WHERE
word.lemma = 'good'
) t
)t1;

mysql query very slow when adding subquery

I have below query , only 800 record taking 5 minits to run, can you some help please
SELECT
vtiger_salesorder.salesorderid,vtiger_salesorder.salesorder_no,vtiger_salesorder.sostatus,
(SELECT se.s_date
FROM
softMax_events as se
INNER JOIN vtiger_salesorder as bm ON bm.salesorderid = se.orderNum
where (bm.sostatus = 'Order' AND se.orderNum = vtiger_salesorder.salesorderid) AND se.appointTyp='60'
group by bm.salesorderid Limit 0,1) As sdate
FROM
vtiger_salesorder
Inner Join vtiger_crmentity ON vtiger_salesorder.salesorderid = vtiger_crmentity.crmid
WHERE (vtiger_salesorder.sostatus = 'Order')
and ( vtiger_crmentity.deleted<>'1')
Try this query, hope so this will help you,
SELECT vtiger_salesorder.salesorderid,vtiger_salesorder.salesorder_no,vtiger_salesorder.sostatus,se.s_date
FROM vtiger_salesorder
Inner Join vtiger_crmentity ON vtiger_salesorder.salesorderid = vtiger_crmentity.crmid
INNER JOIN softMax_events se ON se.orderNum = salesorderid
WHERE (vtiger_salesorder.sostatus = 'Order') AND/OR
se.orderNum = vtiger_salesorder.salesorderid AND se.appointTyp='60'
and ( vtiger_crmentity.deleted<>'1')
Edit:
I noticed that there is some relation between vtiger_salesorder and softMax_events and you can use a join for both table, and in this way you can remove that inner query, i tried it you may test it. this will help you for sure after a bit modification.

Duplicates in MySQL query

I want to do the query directly a Magento database in MySQL but it gives me duplicates. Could you please help me?
SELECT DISTINCT
`catalog_product_entity`.`sku`
, `catalog_product_flat_1`.`name`
, `catalog_product_entity_text`.`value` AS `description`
, `catalog_product_flat_1`.`url_key`
, `catalog_product_flat_1`.`small_image`
, `catalog_product_flat_1`.`price`
, `catalog_product_flat_1`.`special_price`
, `catalog_product_flat_1`.`designer_value`
, `catalog_product_flat_1`.`color_value`
FROM
`ac_magento_gold`.`catalog_product_flat_1`
INNER JOIN `ac_magento_gold`.`catalog_product_entity`
ON (`catalog_product_flat_1`.`entity_id` = `catalog_product_entity`.`entity_id`) AND (`catalog_product_entity`.`sku` = `catalog_product_flat_1`.`sku`) AND (`catalog_product_flat_1`.`sku` NOT REGEXP '(SZ|SIZE|GIFT)')
INNER JOIN `ac_magento_gold`.`catalog_product_entity_text`
ON (`catalog_product_entity_text`.`entity_id` = `catalog_product_entity`.`entity_id`) AND (`catalog_product_entity_text`.`attribute_id`= 61)
INNER JOIN `ac_magento_gold`.`cataloginventory_stock_item`
ON (`cataloginventory_stock_item`.`product_id` = `catalog_product_entity`.`entity_id`) AND (`cataloginventory_stock_item`.`product_id` = `catalog_product_flat_1`.`entity_id`) AND (`catalog_product_entity_text`.`entity_id` = `cataloginventory_stock_item`.`product_id`) AND (`cataloginventory_stock_item`.is_in_stock = 1) LIMIT 6;
If you have multiple websites or stores (or even stock_id), that could be the reason you are getting duplicates. You need to specify the relevant store_id or website_id or stock_id in your joins.
For example,
INNER JOIN `ac_magento_gold`.`catalog_product_entity_text`
ON (`catalog_product_entity_text`.`entity_id` = `catalog_product_entity`.`entity_id`)
AND (`catalog_product_entity_text`.`attribute_id`= 61)
should be
INNER JOIN `ac_magento_gold`.`catalog_product_entity_text`
ON (`catalog_product_entity_text`.`entity_id` = `catalog_product_entity`.`entity_id`)
AND (`catalog_product_entity_text`.`attribute_id`= 61)
AND `catalog_product_entity_text`.`store_id` = 0
or whatever your store_id is. Actually, the query makes even more sense (to me at least) with the parentheses rearranged like so:
INNER JOIN `ac_magento_gold`.`catalog_product_entity_text`
ON (
`catalog_product_entity_text`.`entity_id` = `catalog_product_entity`.`entity_id`
AND `catalog_product_entity_text`.`attribute_id`= 61
AND `catalog_product_entity_text``.store_id` = 0
)
You might also have to rewrite the following:
INNER JOIN `ac_magento_gold`.`cataloginventory_stock_item`
ON (`cataloginventory_stock_item`.`product_id` = `catalog_product_entity`.`entity_id`)
AND (`cataloginventory_stock_item`.`product_id` = `catalog_product_flat_1`.`entity_id`)
AND (`catalog_product_entity_text`.`entity_id` = `cataloginventory_stock_item`.`product_id`)
AND (`cataloginventory_stock_item`.is_in_stock = 1)
to:
INNER JOIN `ac_magento_gold`.`cataloginventory_stock_item`
ON (`cataloginventory_stock_item`.`product_id` = `catalog_product_entity`.`entity_id`
AND `cataloginventory_stock_item`.`product_id` = `catalog_product_flat_1`.`entity_id`
AND `catalog_product_entity_text`.`entity_id` = `cataloginventory_stock_item`.`product_id`
AND `cataloginventory_stock_item`.is_in_stock = 1
AND `cataloginventory_stock_item`.`stock_id` = 1)
again, depending on which stock_id you are interested in. As far as I know, catalog_product_entity only contains one of each entity_id, so no website_id, store_id, or stock_id has to be specified. I also believe that catalog_product_flat_1 is specific to one store_id or website_id or something, but I am not sure.

MySQL LIMIT in a Correllated Subquery

I have a correlated subquery that will return a list of quantities, but I need the highest quantity, and only the highest. So I tried to introduce an order by and a LIMIT of 1 to achieve this, but MySQL throws an error stating it doesn't yet support limits in subqueries. Any thoughts on how to work around this?
SELECT Product.Name, ProductOption.Name, a.Qty, a.Price, SheetSize.UpgradeCost,
FinishType.Name, FinishOption.Name, FinishTierPrice.Qty, FinishTierPrice.Price
FROM `Product`
JOIN `ProductOption`
ON Product.idProduct = ProductOption.Product_idProduct
JOIN `ProductOptionTier` AS a
ON a.ProductOption_idProductOption = ProductOption.idProductOption
JOIN `PaperSize`
ON PaperSize.idPaperSize = ProductOption.PaperSize_idPaperSize
JOIN `SheetSize`
ON SheetSize.PaperSize_idPaperSize = PaperSize.idPaperSize
JOIN `FinishOption`
ON FinishOption.Product_idProduct = Product.idProduct
JOIN `FinishType`
ON FinishType.idFinishType = FinishOption.Finishtype_idFinishType
JOIN `FinishTierPrice`
ON FinishTierPrice.FinishOption_idFinishOption = FinishOption.idFinishOption
WHERE Product.idProduct = 1
AND FinishTierPrice.idFinishTierPrice IN (SELECT FinishTierPrice.idFinishTierPrice
FROM `FinishTierPrice`
WHERE FinishTierPrice.Qty <= a.Qty
ORDER BY a.Qty DESC
LIMIT 1)
This is a variation of the greatest-n-per-group problem that comes up frequently.
You want the single row form FinishTierPrice (call it p1), matching the FinishOption and with the greatest Qty, but still less than or equal to the Qty of the ProductOptionTier.
One way to do this is to try to match a second row (p2) from FinishTierPrice that would have the same FinishOption and a greater Qty. If no such row exists (use an outer join and test that it's NULL), then the row found by p1 is the greatest.
SELECT Product.Name, ProductOption.Name, a.Qty, a.Price, SheetSize.UpgradeCost,
FinishType.Name, FinishOption.Name, FinishTierPrice.Qty, FinishTierPrice.Price
FROM `Product`
JOIN `ProductOption`
ON Product.idProduct = ProductOption.Product_idProduct
JOIN `ProductOptionTier` AS a
ON a.ProductOption_idProductOption = ProductOption.idProductOption
JOIN `PaperSize`
ON PaperSize.idPaperSize = ProductOption.PaperSize_idPaperSize
JOIN `SheetSize`
ON SheetSize.PaperSize_idPaperSize = PaperSize.idPaperSize
JOIN `FinishOption`
ON FinishOption.Product_idProduct = Product.idProduct
JOIN `FinishType`
ON FinishType.idFinishType = FinishOption.Finishtype_idFinishType
JOIN `FinishTierPrice` AS p1
ON p1.FinishOption_idFinishOption = FinishOption.idFinishOption
AND p1.Qty <= a.Qty
LEFT OUTER JOIN `FinishTierPrice` AS p2
ON p2.FinishOption_idFinishOption = FinishOption.idFinishOption
AND p2.Qty <= a.Qty AND (p2.Qty > p1.Qty OR p2.Qty = p1.Qty
AND p2.idFinishTierPrice > p1.idFinishTierPrice)
WHERE Product.idProduct = 1
AND p2.idFinishTierPrice IS NULL