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
Related
I have a huge select query where i have to join more than 85 tables. I keep getting an error when running the query, if I re-run the query when shrinking the overall statement it runs fine.
See a portion of the join below, it does that all the way to table 85:
select $imploded_tables from $apps a
left join $mobile_c0 $m_c0 on $apps.id = $m_c0.id
left join $mobile_c1 $m_c1 on $m_c0.id = $m_c1.id
left join $mobile_c2 $m_c2 on $m_c1.id = $m_c2.id
left join $mobile_c3 $m_c3 on $m_c2.id = $m_c3.id
left join $mobile_c4 $m_c4 on $m_c3.id = $m_c4.id
left join $mobile_c5 $m_c5 on $m_c4.id = $m_c5.id
left join $mobile_c6 $m_c6 on $m_c5.id = $m_c6.id
left join $mobile_c7 $m_c7 on $m_c6.id = $m_c7.id
left join $mobile_c8 $m_c8 on $m_c7.id = $m_c8.id
left join $mobile_c9 $m_c9 on $m_c8.id = $m_c9.id
left join $mobile_c10 $m_c10 on $m_c9.id = $m_c10.id
...
...
Mysql Documentation
The maximum number of tables that can be referenced in a single join is 61.
As per #sf_admin answer the maximum no of join is 61 , so you can do something like below
select imploded_tables from apps a
JOIN
(
SELECT * from mobile_c0
UNION
SELECT * from mobile_c1
....
)tmp
where(tmp.id=a.id)
It might not 100% percent answer your question but this is some work around I did
I've taken over a project that is a real mess so I've left with bad code structure that is forcing me to basically program in SQL. So changing the way of calculating this is for now not an option.
I have $sqlAdd variable that i need to populate in function and then concatenate that to main query to count number of lost tickets.
Main query looks like this:
$sql = "SELECT COUNT(*) as num_tickets, SUM(t.total_amount) as total_payin, SUM(t.total_payout) as total_payout
FROM t WHERE t.tickettime BETWEEN '$dateFrom' AND '$dateTo' AND t.bsid = $bsID
$sqlAdd";
So $sqlAdd is getting from another function
$sqlAdd = getSqlAdd();
And in that function i have this:
$sqlAdd = " AND 'WON' NOT IN (
SELECT GROUP_CONCAT(tr.ticketstatus)
FROM tr INNER JOIN m ON tr.ticketid = m.ticketid
WHERE tr.ticketid = t.ticketid GROUP BY m.ticket_groupid
)
AND 'PAYEDOUT' NOT IN (
SELECT GROUP_CONCAT(tr.ticketstatus)
FROM tr INNER JOIN m ON tr.ticketid = m.ticketid
WHERE tr.ticketid = t.ticketid GROUP BY m.ticket_groupid
)
AND 'CLOSED' NOT IN (
SELECT GROUP_CONCAT(tr.ticketstatus)
FROM tr INNER JOIN m ON tr.ticketid = m.ticketid
WHERE tr.ticketid = t.ticketid GROUP BY m.ticket_groupid
)
AND 'OPEN' NOT IN (
SELECT GROUP_CONCAT(tr.ticketstatus)
FROM tr INNER JOIN m ON tr.ticketid = m.ticketid
WHERE tr.ticketid = t.ticketid GROUP BY m.ticket_groupid
)";
GROUP_CONCAT(tr.ticketstatus) is getting me these rows when i execute it
CLOSED,CLOSED,CLOSED
PAYEDOUT,PAYEDOUT
CLOSED,CLOSED
WON,LOST
LOST,WON,WON,WON,WON,WON
CLOSED,CLOSED
LOST,LOST,WON
WON,WON,WON,LOST,LOST,WON,WON
LOST
I just want to count rows that have only LOST status in it. So the result should be 1. But i keep getting 7. It it counting every LOST status in results.
You would seem to want something like this:
SELECT COUNT(*) as num_tickets, SUM(t.total_amount) as total_payin,
SUM(t.total_payout) as total_payout
FROM t
WHERE t.tickettime BETWEEN '$dateFrom' AND
'$dateTo' AND t.bsid = $bsID AND
NOT EXISTS (SELECT 1
FROM tr NATURAL JOIN
m NATURAL JOIN
tg
WHERE tr.ticketid = t.ticketid AND
tr.ticketstatus IN ('WON', 'PAYEDOUT', 'CLOSED', 'OPEN')
);
Some notes:
GROUP_CONCAT() is not appropriate for this type of comparison. In SQL, you don't convert lists to strings and then do comparisons -- at least if you want performance.
You should avoid NATURAL JOIN. A small change to any of the tables can totally change the semantics of the query. In addition, it is unclear what the JOIN keys are. I would recommend USING instead.
You might want tr.ticketstatus NOT IN ('LOST') in the subquery.
So i've wrote very ugly query that is probably slow but its working i'm getting results that i need.
$sql = " AND ticket_groupid IN (
SELECT tg FROM t as tt
NATURAL JOIN tr NATURAL JOIN m
WHERE tt.tickettime BETWEEN '$dateFrom' AND '$dateTo' AND tt.bsid = $bsid
AND 'LOST' IN (
SELECT GROUP_CONCAT(tr.ticketstatus)
FROM tr NATURAL JOIN m as mm
WHERE mm.ticket_groupid = m.ticket_groupid
)
GROUP BY mm.ticket_groupid )"
i am using this query to fetching products.the product table has 302,716 rows.it is taking too much time to execute around 2-3 minutes.but when i removed order by it takes less time.
SELECT DISTINCT
product.ProductID,
company.CompanyName
FROM
product
INNER JOIN company
ON company.CompanyID = product.CompanyID
LEFT JOIN company_csv_data
ON company.CompanyID = company_csv_data.CompanyID
LEFT JOIN productcategory
ON product.ProductID = productcategory.ProductID
LEFT JOIN category
ON category.CategoryID = productcategory.CategoryID
LEFT JOIN supplier
ON product.supplier = supplier.id
LEFT JOIN template_vouchers tm
ON product.ProductID = tm.voucher_id
WHERE company.turn_on = 1
AND product.ProductEndDate >= CURRENT_DATE
AND turn_off = 1
GROUP BY product.ProductID
ORDER BY clicks DESC,
product.CodeOpen DESC,
product.Online,
product.EntryDate DESC
LIMIT 0, 15
You could improve the query's speed/performance by creating indexes for the columns in the select and where clauses (this will slow down insert, delete and update statements..)
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.
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.