I'm working on the layered navigation module with Prestashop solution,
I'm trying to optimize a Sql query which create a tmp table to execute it and by this way create a bottleneck in mysql.
This is the query :
SELECT p.*, p.id_category_default, pl.available_later, pl.description_short, pl.link_rewrite, pl.name, i.id_image, il.legend, m.name manufacturer_name, DATEDIFF(p.`date_add`, DATE_SUB(NOW(), INTERVAL 30 DAY)) > 0 AS new
FROM `ps_category_product` cp
LEFT JOIN ps_category c ON (c.id_category = cp.id_category)
LEFT JOIN `ps_product` p ON p.`id_product` = cp.`id_product`
LEFT JOIN ps_product_lang pl ON (pl.id_product = p.id_product)
LEFT JOIN ps_image i ON (i.id_product = p.id_product AND i.cover = 1)
LEFT JOIN ps_image_lang il ON (i.id_image = il.id_image AND il.id_lang = 2)
LEFT JOIN ps_manufacturer m ON (m.id_manufacturer = p.id_manufacturer)
WHERE p.`active` = 1 AND c.nleft >= 2 AND c.nright <= 29 AND c.active = 1 AND pl.id_lang = 2
AND p.id_product IN (74,78,130,146,168,169,178,195,...,297,302,1986,1987,1988,1993,1999,2000,2001)
GROUP BY p.id_product ORDER BY p.date_upd desc LIMIT 0,48
I know the tmp table is created because of the GROUP BY but I don't know how to remove it. If the same process could be done with PHP instead of SQL, it could be a solution.
Thanks in advance.
Related
This is my query without variant options
SELECT p.*, pd.`name` AS `product_name`
FROM `product` AS `p`
LEFT JOIN `product_description` AS `pd` ON p.`id` = pd.`product_id`
LEFT JOIN `product_to_variant` AS `pv` ON p.`id` = pv.`product_id`
WHERE p.`status` = 0
GROUP BY p.`id`
ORDER BY p.`id` DESC;
SQLFiddle: http://sqlfiddle.com/#!9/8955b/5
and the follwing query has variant options but it doesn't work
SELECT p.*, pd.`name` AS `product_name`
FROM `product` AS `p`
LEFT JOIN `product_description` AS `pd` ON p.`id` = pd.`product_id`
LEFT JOIN `product_to_variant` AS `pv` ON p.`id` = pv.`product_id`
WHERE p.`status` = 0
AND (pv.`feature_id` = 2 AND pv.`variant_id` = 6)
AND (pv.`feature_id` = 3 AND pv.`variant_id` = 11)
GROUP BY p.`id`
ORDER BY p.`id` DESC;
and I also trying to query but there is no output
SELECT pv.* FROM `product_to_variant` AS `pv`
WHERE (pv.`feature_id` = 2 AND pv.`variant_id` = 2)
AND (pv.`feature_id` = 3 AND pv.`variant_id` = 11)
Do you have any other idea how to receive the products: 14, 15 by specific variant_id 6 AND 11 http://prntscr.com/ect2oh
Here is one method to do what you want:
SELECT p.*, pd.name AS product_name
FROM product p LEFT JOIN
product_description pd
ON p.id = pd.product_id JOIN
product_to_variant pv
ON p.id = pv.product_id
WHERE p.status = 0 AND
((pv.feature_id = 2 AND pv.variant_id = 6) OR
(pv.feature_id = 3 AND pv.variant_id = 11)
)
GROUP BY p.id
HAVING COUNT(DISTINCT feature_id) = 2
ORDER BY p.id DESC;
Notes:
No row can meet your original conditions. Because a column cannot have two values at the same time. Hence the OR rather than AND.
The HAVING clause checks that both values match.
There is no need for a LEFT JOIN to pv, because you are checking values from that table in the WHERE clause -- there have to be matches.
The LEFT JOIN to pa is probably also unnecessary.
Using backticks everywhere just makes the query harder to write and to read.
Maybe like this:
SELECT pv.* FROM `product_to_variant` AS `pv`
WHERE (pv.`feature_id` = 2 AND pv.`variant_id` = 2)
OR (pv.`feature_id` = 3 AND pv.`variant_id` = 11)
Instead of AND, which says, you need both feature_id and variant_id in the results, use OR because it takes both.
Query:
SELECT em.`Full_Name`,em.`VEEVA_Employee_ID`,COUNT(dm.`Account_ID`) AS
No_of_Doctors ,COUNT(p.`Doctor_Id`)AS No_of_Doctors_profiled,rt.`target` AS
Target_New_Rxn_for_the_month,SUM(rp.`Planned_Rx`) AS
Planned_New_Rxn,COUNT(ap.`Act_Plan`) AS No_of_Doctors_planned,
COUNT(CASE WHEN ar.`Activity_Done`='Yes' THEN 1 END) AS checkk
FROM ( SELECT `VEEVA_Employee_ID`,`Full_Name` FROM Employee_Master
WHERE `Reporting_VEEVA_ID` = 'gi00145822') AS em
LEFT JOIN (SELECT d.`Account_ID`, ed.`VEEVA_Employee_ID` FROM Doctor_Master d
INNER JOIN Employee_Doc ed ON ed.`VEEVA_Account_ID` = d.`Account_ID` AND `ed`.`Status`='1'
WHERE `VEEVA_Employee_ID` IN (SELECT `VEEVA_Employee_ID` FROM Employee_Master WHERE `Reporting_VEEVA_ID` = 'gi00145822')
AND d.`Individual_Type` = 'Doctor' ) AS dm ON em.`VEEVA_Employee_ID` = dm.`VEEVA_Employee_ID`
LEFT JOIN (SELECT `Doctor_Id`, `VEEVA_Employee_ID` FROM Profiling WHERE `Product_Id` = 6 AND `STATUS` = 'Submitted' AND `Cycle` = 2 GROUP BY `Doctor_Id`, `VEEVA_Employee_ID`) AS
p ON em.`VEEVA_Employee_ID` = p.`VEEVA_Employee_ID` AND dm.`Account_ID` = p.`Doctor_Id`
LEFT JOIN Rx_Target rt ON em.`VEEVA_Employee_ID`=rt.`VEEVA_Employee_ID`AND rt.`Status`='Submitted' AND rt.`Product_Id`=6 AND rt.`Month`=12 AND rt.`Year`=2016
LEFT JOIN Rx_Planning rp ON dm.`Account_ID` = rp.`Doctor_Id` AND rp.`Approve_Status` ='Approved' AND rp.`Product_Id`=6 AND rp.`Month`=12 AND rp.`Year`=2016 AND rp.`VEEVA_Employee_ID` = em.`VEEVA_Employee_ID`
LEFT JOIN Activity_Planning ap ON dm.`Account_ID` = ap.`Doctor_Id` AND ap.`Approve_Status` = 'Approved' AND ap.`Product_Id`=6 AND ap.`Month`=12 AND ap.`Year`=2016 AND em.`VEEVA_Employee_ID` = ap.`VEEVA_Employee_ID`
LEFT JOIN Activity_Reporting ar ON dm.`Account_ID` = ar.`Doctor_Id` AND ar.`Approve_Status` = 'Approved' AND ar.`Product_Id`=6 AND ar.`Month`=12 AND ar.`Year`=2016 AND em.`VEEVA_Employee_ID` = ar.`VEEVA_Employee_ID`
GROUP BY em.`VEEVA_Employee_ID`
It executing perfectly on sqlyog but its not working with CI $this->db->query($sql)
Actually i got the solution.
its exits the current process in middle.
i allocate resources.
ini_set('max_execution_time',300);
and
ini_set('memory_limit','128M');
and works perfectly.
anyway thank you all.
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
Brain bad. Something isn't clicking that I know is probably simple. I'm trying my best to avoid a subquery but it may be unavoidable.
There are 11 records in the left table [cards_types] and between 1 and 11 records in the right table [users_cards]. I need to return all records from the left table and whatever is found in the right table. The only caveat to the right table is doing some IF / ELSE statements to return 0 values if it card_types.id is not found in users_cards. Also, there is a foreign key constraint on cards_types.id => users_cards.type_id (if it matters).
Query
SELECT
t.id,
t.slug,
t.label AS type_label,
t.points AS point_value,
IF (c.mtg_id IS NULL, 0, c.mtg_id) AS mtg_id,
IF (c.label IS NULL, 0, c.label ) AS card_label,
IF (uc.points IS NULL, 0, uc.points ) AS card_score
FROM cards_types t
JOIN users_cards uc
ON uc.type_id = t.id
JOIN cards c
ON c.id = uc.card_id
WHERE uc.user_id = 1
AND uc.season_id = 1
ORDER BY t.priority ASC
You are currently using an INNER JOIN, change it to a LEFT JOIN. I also moved your WHERE clause filters to the JOIN so you will return all rows from cards_type. If you leave the filters in the WHERE clause, then it will act like an INNER JOIN:
SELECT
t.id,
t.slug,
t.label AS type_label,
t.points AS point_value,
COALESCE(c.mtg_id, 0) AS mtg_id,
COALESCE(c.label, 0) AS card_label,
COALESCE(uc.points, 0) AS card_score
FROM cards_types t
LEFT JOIN users_cards uc
ON uc.type_id = t.id
AND uc.user_id = 1 -- < -- move the where filters here
AND uc.season_id = 1
LEFT JOIN cards c
ON c.id = uc.card_id
ORDER BY t.priority ASC
try with left join like that
SELECT
t.id,
t.slug,
t.label AS type_label,
t.points AS point_value,
COALESCE(c.mtg_id, 0) AS mtg_id,
COALESCE(c.label, 0) AS card_label,
COALESCE(uc.points, 0) AS card_score
FROM cards_types t
LEFT JOIN users_cards uc
ON uc.type_id = t.id
AND uc.user_id = 1
AND uc.season_id = 1
LEFT JOIN cards c
ON c.id = uc.card_id
ORDER BY t.priority ASC
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.