I m using following mysql query to fetch some desired result but problem is that it is taking more time. Currently execution time for this query is 7456 ms which is unacceptable for my project, I want to optimize this query any idea?.
SELECT *, DATEDIFF(NOW(),ticketstatus_tbl.updation_date) AS problem_age,images_tbl.image_path
FROM ticketstatus_tbl
LEFT JOIN question_tbl ON ticketstatus_tbl.question_id = question_tbl.question_id
LEFT JOIN ticketing_tbl ON ticketstatus_tbl.related_ticket_id = ticketing_tbl.ticket_id
LEFT JOIN department_tbl ON question_tbl.question_dept = department_tbl.department_id
LEFT JOIN branch_tbl ON ticketstatus_tbl.branch_id = branch_tbl.id
LEFT JOIN images_tbl ON images_tbl.question_id = ticketstatus_tbl.question_id and images_tbl.branch_id = ticketstatus_tbl.branch_id
WHERE (ticketstatus_tbl.ticket_status NOT IN ('Close')
AND question_tbl.is_active_question = 1
AND ticketstatus_tbl.display_status = '1'
AND ticketstatus_tbl.flag_color = 'Yellow'
AND department_tbl.department_name = 'Admin')order by ticket_number ASC LIMIT 0 ,5
Thanks
First, you do not need all the left outer join, because your where clause is undoing most of them. My guess is all could be turned into inner joins, but at the minimum:
SELECT *, DATEDIFF(NOW(),ticketstatus_tbl.updation_date) AS problem_age,images_tbl.image_path
FROM ticketstatus_tbl
JOIN question_tbl ON ticketstatus_tbl.question_id = question_tbl.question_id
LEFT JOIN ticketing_tbl ON ticketstatus_tbl.related_ticket_id = ticketing_tbl.ticket_id
JOIN department_tbl ON question_tbl.question_dept = department_tbl.department_id
LEFT JOIN branch_tbl ON ticketstatus_tbl.branch_id = branch_tbl.id
LEFT JOIN images_tbl ON images_tbl.question_id = ticketstatus_tbl.question_id and images_tbl.branch_id = ticketstatus_tbl.branch_id
WHERE ticketstatus_tbl.ticket_status NOT IN ('Close')
AND question_tbl.is_active_question = 1
AND ticketstatus_tbl.display_status = '1'
AND ticketstatus_tbl.flag_color = 'Yellow'
AND department_tbl.department_name = 'Admin'
order by ticket_number ASC LIMIT 0 ,5;
Second, you are doing filtering onticketstatus_tbl. You should have a composite index on ticketstatus_tbl(display_status, flag_color, ticket_status, question_id). If you can, change the ticket_status not in ('Close') to an affirmative statement: ticket_status in (Open, 'In Progress', . . .). This makes it easier to use the index.
This is a start.
Related
I have five tables with join. This query takes more than 5 sec to execute. I have four queries like the one below, so my PHP page takes more than 30 sec to load. I need to improve the performance. Could you please help me? I have struggled for a week. I added indexing.
MY QUERY
SELECT f.SortField , f.id
FROM tbl_store_brands AS sb
INNER JOIN tbl_products AS p
ON sb.categoryID = p.pkCategory AND sb.brandID = p.pkBrand
INNER JOIN ModelPrice AS mp ON (p.id = mp.product_id)
INNER JOIN Brand_Data AS bd ON bd.pkID = p.pkBrand+0
INNER JOIN tbl_filters AS f
ON (
p.pkID = f.pkID and
p.pkCategory = f.Category AND
p.cgSlug = 'bathroom-fixtures'
)
WHERE mp.Available = 1
GROUP BY f.SortField
ORDER BY if (
f.SortField = 'CAPACITY' OR
f.SortField = 'WIDTH' OR
f.SortField = 'HEIGHT' OR
f.SortField = 'DEPTH', 4, f.ValueDisplayOrder
) ASC
MY Query EXPLANATION
Few modification can be done, to improve you query performance.
1. Add index for ValueDisplayOrder, this will improve the sorting performance.
2. Avoid in query per functioning. Remove the "p.pkBrand+0", this add the execution process time. If possible remove the if clause from order by and do the ordering in your PHP code.
3. Move the "p.cgSlug = 'bathroom-fixtures'" code to on clause of product table join to narrow down the inner join result.
Your modified query will look like:
SELECT f.SortField , f.id
FROM tbl_store_brands AS sb
INNER JOIN tbl_products AS p
ON sb.categoryID = p.pkCategory AND sb.brandID = p.pkBrand AND p.cgSlug = 'bathroom-fixtures'
INNER JOIN ModelPrice AS mp ON (p.id = mp.product_id)
INNER JOIN Brand_Data AS bd ON bd.pkID = p.pkBrand
INNER JOIN tbl_filters AS f
ON (
p.pkID = f.pkID and
p.pkCategory = f.Category
)
WHERE mp.Available = 1
GROUP BY f.SortField
ORDER BY f.ValueDisplayOrder
ASC
I have a coin table which provides all the information about uploaded coins, and there is an owner table which gives information about the owner of a particular coin. In the coin_owners table, there is field 'ownership_mode' which will be either 'transfer' or 'Reward'. If the mode is 'transfer', I want to left join the transfer table, and if the mode is 'Reward', I want to join the rewards table.
I have tried this using the CASE clause, but it's not working.
The query I tried is:
SELECT * , coins.id AS CoinId FROM coins
LEFT JOIN coin_owners ON coin_owners.coin_id = coins.id
LEFT JOIN (CASE WHEN coin_owners.`ownership_mode` = 'transfer' THEN transfer_detail ON transfer_detail.transfer_to = coin_owners.current_owner
AND transfer_detail.transfer_from = SUBSTRING_INDEX( coin_owners.previous_owner, ',', '-1' )
WHEN coin_owners.`ownership_mode` = 'Reward' THEN rewards ON rewards.`coin_ids` = coin_owners.coin_id
AND coin_owners.`ownership_mode` = 'Reward'
AND STATUS = '0'
) WHERE coins.id ='".validString($_REQUEST["coinId"])."' LIMIT 0,1
Thanks a lot...but i have used the following query and it works fine >---->
SELECT * , coins.id AS CoinId FROM coins
LEFT JOIN coin_owners ON coin_owners.coin_id = coins.id
LEFT JOIN transfer_detail ON transfer_detail.coin_id = coin_owners.coin_id AND transfer_detail.transfer_to = coin_owners.current_owner AND transfer_detail.transfer_from = SUBSTRING_INDEX( coin_owners.previous_owner, ',', '-1' ) AND coin_owners.`ownership_mode` = 'transfer'
LEFT JOIN rewards ON rewards.`coin_ids` = coin_owners.coin_id AND coin_owners.`ownership_mode` = 'Reward' AND STATUS = '0'
WHERE coins.id ='".mysql_real_escape_string(trim($_REQUEST["coinId"]))."' LIMIT 0,1
thanks to all of you for the help
CASE is an expression, you can't use that inside a table reference. You'll have to handle both cases using separate queries which you can then combine using UNION:
(
SELECT …
FROM coins
LEFT JOIN coin_owners ON coin_owners.coin_id = coins.id
LEFT JOIN transfer_detail
ON transfer_detail.transfer_to = coin_owners.current_owner
AND transfer_detail.transfer_from =
SUBSTRING_INDEX(coin_owners.previous_owner, ',', '-1')
WHERE coin_owners.ownership_mode = 'transfer'
AND coins.id = ?
UNION ALL
SELECT …
FROM coins
LEFT JOIN coin_owners ON coin_owners.coin_id = coins.id
LEFT JOIN rewards
ON rewards.coin_ids = coin_owners.coin_id
AND STATUS = '0'
WHERE coin_owners.ownership_mode = 'Reward'
AND coins.id = ?
)
LIMIT 0,1
You'll have to make sure that the columns of both queries match, perhaps by insering NULL values into those which don't have a corresponding value in one of the queries.
Also note that you should not insert request parameters into the string the way you did unless you made absolutely sure that the passed value is safe against SQL injection. Better to use prepared statements, which is why I substituted ? in my query instead.
I have this large query, and I just need to filter out any results where the tbl_dealinterest.Active = 'n'. There sometimes isn't an entry in that table for the product, and sometimes it might there might be and entry and set to y.
Here is the large ugly query:
SELECT tbl_product.id, tbl_productspecification.id AS specificationId,
tbl_product.ProductId, tbl_seller.CompanyName, tbl_product.ProductName, tbl_product.Description, mst_Categories.id AS 'Category',
tbl_productspecification.RetailPrice, tbl_productspecification.SalePrice,
tbl_product.image, tbl_productspecification.Discount, tbl_product.EndTime, tbl_product.Seller_Id, tbl_dealinterest.Active AS thumbsActive
FROM tbl_product
LEFT OUTER JOIN tbl_seller ON tbl_seller.SelId = tbl_product.Seller_Id
LEFT OUTER JOIN mst_Categories ON (mst_Categories.id = tbl_product.Category OR mst_Categories.id = tbl_product.SubCategory)
LEFT OUTER JOIN tbl_productspecification ON tbl_productspecification.ProductId = tbl_product.ProductId
LEFT OUTER JOIN mst_image ON mst_image.Product = tbl_product.ProductId
LEFT OUTER JOIN tbl_dealinterest ON tbl_dealinterest.ProductId = tbl_product.ProductId AND tbl_dealinterest.BuyerId = '$token'
WHERE tbl_product.Active='y'
AND tbl_product.StartTime <= '".date("Y-m-d H:i:s")."'
AND tbl_product.EndTime > '".date("Y-m-d")." 06:00:00'
".$subquery."
GROUP BY tbl_productspecification.ProductId";
Thanks for any suggestions.
SELECT ...
WHERE tbl_product.Active='y'
AND (tbl_dealinterest.Active <> 'n' OR tbl_dealinterest.Active IS NULL)
...
LEFT OUTER JOIN tbl_dealinterest ON (tbl_dealinterest.ProductId = tbl_product.ProductId
AND tbl_dealinterest.BuyerId = '$token'
AND tbl_dealinterest.Active<>'n')
I currently have this left join as part of a query:
LEFT JOIN movies t3 ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The trouble is that if there are several movies with the same name and same popularity (don't ask, it just is that way :-) ) then duplicate results are returned.
All that to say, I would like to limit the result of the left join to one.
I tried this:
LEFT JOIN
(SELECT t3.movie_name FROM movies t3 WHERE t3.popularity = 0 LIMIT 1)
ON t1.movie_id = t3.movie_id AND t3.popularity = 0
The second query dies with the error:
Every derived table must have its own alias
I know what I'm asking is slightly vague since I'm not providing the full query, but is what I'm asking generally possible?
The error is clear -- you just need to create an alias for the subquery following its closing ) and use it in your ON clause since every table, derived or real, must have its own identifier. Then, you'll need to include movie_id in the subquery's select list to be able to join on it. Since the subquery already includes WHERE popularity = 0, you don't need to include it in the join's ON clause.
LEFT JOIN (
SELECT
movie_id,
movie_name
FROM movies
WHERE popularity = 0
ORDER BY movie_name
LIMIT 1
) the_alias ON t1.movie_id = the_alias.movie_id
If you are using one of these columns in the outer SELECT, reference it via the_alias.movie_name for example.
Update after understanding the requirement better:
To get one per group to join against, you can use an aggregate MAX() or MIN() on the movie_id and group it in the subquery. No subquery LIMIT is then necessary -- you'll receive the first movie_id per name withMIN() or the last with MAX().
LEFT JOIN (
SELECT
movie_name,
MIN(movie_id) AS movie_id
FROM movies
WHERE popularity = 0
GROUP BY movie_name
) the_alias ON t1.movie_id = the_alias.movie_id
LEFT JOIN movies as m ON m.id = (
SELECT id FROM movies mm WHERE mm.movie_id = t1.movie_id
ORDER BY mm.id DESC
LIMIT 1
)
you could try to add GROUP BY t3.movie_id to the first query
Try this:
LEFT JOIN
(
SELECT t3.movie_name, t3.popularity
FROM movies t3 WHERE t3.popularity = 0 LIMIT 1
) XX
ON t1.movie_id = XX.movie_id AND XX.popularity = 0
On MySQL 5.7+ use ANY_VALUE & GROUP_BY:
SELECT t1.id,t1.movie_name, ANY_VALUE(t3.popularity) popularity
FROM t1
LEFT JOIN t3 ON (t3.movie_id=t1.movie_id AND t3.popularity=0)
GROUP BY t1.id
more info
LEFT JOIN only first row
https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
Easy solution to left join the 1 most/least recent row is using select over ON phrase
SELECT A.ID, A.Name, B.Content
FROM A
LEFT JOIN B
ON A.id = (SELECT MAX(id) FROM B WHERE id = A.id)
Where A.id is the auto-incremental primary key.
LEFT JOIN (
SELECT id,movie_name FROM movies GROUP BY id
) as m ON (
m.id = x.id
)
// Mysql
SELECT SUM(db.item_sales_nsv) as total FROM app_product_hqsales_otc as db
LEFT JOIN app_item_target_otc as it ON
db.id = (SELECT MAX(id) FROM app_item_target_otc as ot WHERE id = db.id)
and db.head_quarter = it.hqcode
AND db.aaina_item_code = it.aaina_item_code AND db.month = it.month
AND db.year = it.year
WHERE db.head_quarter = 'WIN001' AND db.month = '5' AND db.year = '2022' AND db.status = '1'
I have this query:
SELECT a.apartment_id, a.building_id, a.apartment_num, a.floor, at.app_type_desc_en AS app_type_desc,
(SELECT ROW(e.e_name, ot.otype_desc_en)
FROM TABLE_TENANTS t INNER JOIN TABLE_OWNERSHIP_TYPES ot ON ot.otype_id=t.ownership_type INNER JOIN TABLE_ENTITIES e ON
t.entity_id = e.entity_id
WHERE a.apartment_id = t.apartment_id AND t.building_id = a.building_id
ORDER BY t.ownership_type DESC LIMIT 1
) AS t_row
FROM TABLE_APARTMENTS a INNER JOIN TABLE_APPARTMENT_TYPES at ON at.app_type_id = a.apartment_type LEFT OUTER JOIN TABLE_TENANTS t ON a.building_id = t.building_id AND t.entity_id=1 AND t.status=true LEFT OUTER JOIN TABLE_COMMITTEE_DELEGATE cd ON
a.building_id = cd.building_id AND cd.entity_id=1 AND cd.status=true
WHERE a.building_id = 1 AND (t.entity_id=1 OR cd.entity_id=1)
ORDER BY a.apartment_num ASC
When I'm using PHP to read the result, I use:
while($ap = pg_fetch_array($_qry)){
}
and trying to read "e_name", which is part of the ROW(e.e_name), but I can't succeed.
Need your ideas ... please.
use pg_fetch_assoc, to retrieve data in asoc-array; But my advice, - use PDO to work with db in PHP.