Optimize mysql query using various join and order by rand() - mysql

I was having trouble on my site, so I went look into mysql slow query log.
Fixed some indexing and also querys without joins now the server load got lower and its running fine.
I still have a query that I havent been able to fix, if any of you have a tip so I can make it better, I would appreciated it.
This is the query
SELECT p.product_id,
p.product_offer_price,
ps.subcategory_name,
pb.brand_name,
pm.model_name,
pm.display_name,
pm.year_from,
pm.year_to
FROM product p
INNER JOIN product_subcategory ps ON ps.subcategory_id = p.product_subcategory_id AND ps.subcategory_category_id = 12
INNER JOIN product_stock pq ON pq.product_id = p.product_id AND pq.product_quantity > 0
INNER JOIN product_photos pp ON pp.product_id = p.product_id
INNER JOIN product_brand pb ON pb.brand_id = p.product_brand_id
INNER JOIN product_model pm ON pm.model_id = p.product_model_id
GROUP BY p.product_id
ORDER BY RAND() LIMIT 4;
This is what explain shows about the query
I was trying to accomplish something like this, but doesn't work
SELECT p.product_id, p.product_offer_price, ps.subcategory_name, pb.brand_name, pm.model_name, pm.display_name, pm.year_from, pm.year_to
FROM product p
INNER JOIN product_subcategory ps ON ps.subcategory_id = p.product_subcategory_id
AND ps.subcategory_category_id =12
INNER JOIN product_stock pq ON pq.product_id = p.product_id
AND pq.product_quantity >0
INNER JOIN product_photos pp ON pp.product_id = p.product_id
INNER JOIN product_brand pb ON pb.brand_id = p.product_brand_id
INNER JOIN product_model pm ON pm.model_id = p.product_model_id
WHERE p.product_id >= FLOOR( 1 + RAND( ) * (
SELECT MAX( product_id )
FROM product ) )
GROUP BY p.product_id
LIMIT 4

Related

SQL LIKE seems not work like i think it should

I have an SELECT statement that has a huge number of left join and I want to filter some out.
When I check how many records i have in total and subtract the records with my LIKE statements, I should get the amount that is not affected by my restrictions.
But when I negate my restriction to get the ones I didn't affect, I get an different number than calculated.
SQL without restrictions (Record count: 13.251.981)
SELECT p.product_number
FROM product p
LEFT JOIN product_category pc on p.id = pc.product_id
LEFT JOIN product_category_tree pct on p.id = pct.product_id
LEFT JOIN product_configurator_setting pcs on p.id = pcs.product_id
LEFT JOIN product_cross_selling pcs2 on p.id = pcs2.product_id
LEFT JOIN product_cross_selling_assigned_products pcsap on p.id = pcsap.product_id
LEFT JOIN product_cross_selling_translation pcst on pcs2.id = pcst.product_cross_selling_id
LEFT JOIN product_custom_field_set pcfs on p.id = pcfs.product_id
LEFT JOIN product_media pm on p.id = pm.product_id
LEFT JOIN product_option po on p.id = po.product_id
LEFT JOIN product_price pp on p.id = pp.product_id
LEFT JOIN product_property pp2 on p.id = pp2.product_id
LEFT JOIN product_review pr on p.id = pr.product_id
LEFT JOIN product_search_keyword psk on p.id = psk.product_id
LEFT JOIN product_tag pt on p.id = pt.product_id
LEFT JOIN product_translation pt2 on p.id = pt2.product_id
LEFT JOIN product_visibility pv on p.id = pv.product_id
With restriction (Record count: 9.285.545)
WHERE p.product_number NOT LIKE 'SW%'
AND p.product_number NOT LIKE '%.%'
AND pt2.name NOT LIKE '%Gutschein'
AND pt2.name NOT LIKE '%Test%'
With negated restriction (Record count: 100.851)
WHERE p.product_number LIKE 'SW%'
OR p.product_number LIKE '%.%'
OR pt2.name LIKE '%Gutschein'
OR pt2.name LIKE '%Test%';
From my calculations i should get 3.966.436 records that don't get affected. (13.251.981 - 9.285.545 = 3.966.436)
But instead I get 100.851
How is that possible?
The solution for me was actually this WHERE:
WHERE p.product_number < 'SW'

Get count from select

my sql code is
select pr.category_id FROM products p
LEFT JOIN products_category_rel pr ON p.id = pr.product_id
left JOIN products_design pd ON p.id = pd.product_id
LEFT JOIN products_producer pp ON pp.id = p.producer_id
group by pr.category_id, p.id
sql return array [1436, 1436, ..., 1436, 1437,...,1437] where the value 1436 is in the array 150 times and 1437 is 100 times
I need retrun columns -> 1436 | 150 , 1437 | 100
can you help me?
Try this:
select pr.category_id, COUNT(pr.category_id) AS category_count
FROM products p
LEFT JOIN products_category_rel pr ON p.id = pr.product_id
left JOIN products_design pd ON p.id = pd.product_id
LEFT JOIN products_producer pp ON pp.id = p.producer_id
group by pr.category_id
order by pr.category_id;

MySQL - #1066 - Not unique table/alias: 'components' with multiple inner joins

I have this query and I am getting error #1066 - Not unique table/alias: 'components'. What seems to be the issue?
SELECT COUNT(*) FROM `products`, `components`, `tradeNames`
INNER JOIN `componentsMap` ON componentsMap.product_id = product.id
INNER JOIN `components` ON componentsMap.component_id = components.id
INNER JOIN `tradeNamesMap` ON .tradeNamesMap.product_id = products.id
INNER JOIN `tradeNames` ON tradeNamesMap.tradeName_id = tradeNames.id
WHERE (((((LOWER(inci) LIKE '%abies%')
OR (trade_name.LOWER(name) LIKE '%abies%'))
OR (components.LOWER(no_cas)='abies'))
OR (components.LOWER(no_einecs)='abies'))
OR (components.LOWER(name)='abies'))
AND (`published`=1)
ORDER BY `trade_name`.`name` DESC
You don't need to list the tables before the INNER JOINs. In fact, simply don't ever use commas in the FROM clause. So:
SELECT COUNT(*)
FROM `products`
INNER JOIN `componentsMap` ON componentsMap.product_id = product.id
INNER JOIN `components` ON componentsMap.component_id = components.id
INNER JOIN `tradeNamesMap` ON tradeNamesMap.product_id = products.id
INNER JOIN `tradeNames` ON tradeNamesMap.tradeName_id = tradeNames.id
WHERE (((((LOWER(inci) LIKE '%abies%')
OR (trade_name.LOWER(name) LIKE '%abies%'))
OR (components.LOWER(no_cas)='abies'))
OR (components.LOWER(no_einecs)='abies'))
OR (components.LOWER(name)='abies'))
AND (`published`=1)
ORDER BY `trade_name`.`name` DESC;
The above query only returns one row because of the COUNT(). The order by suggests that you actually want this information for each trade_name.name. If so, you need a GROUP BY:
SELECT tn.name, COUNT(*)
FROM `products` p INNER JOIN
`componentsMap cm
ON cm.product_id = p.id INNER JOIN
`components` c
ON cm.component_id = c.id INNER JOIN
`tradeNamesMap` tnm
ON tnm.product_id = p.id INNER JOIN
`tradeNames` tn
ON tnm.tradeName_id = tn.id
WHERE ((LOWER(inci) LIKE '%abies%') OR
(tn.LOWER(name) LIKE '%abies%') OR
(c.LOWER(no_cas)='abies') OR
(c.LOWER(no_einecs)='abies') OR
(c.LOWER(name)='abies')
) AND
(`published` = 1)
GROUP BY tn.name
ORDER BY tn.`name` DESC
INNER JOIN `[components]` ON componentsMap.component_id = components.id
AND
SELECT COUNT(*) FROM `products`, [`components`], `tradeNames`
Two components are there.
Just guessing, and untested, but I suspect that something like this would do what you're after...
SELECT n.name
, COUNT(*)
FROM products p
JOIN componentsMap pc
ON pc.product_id = p.id
JOIN components c
ON c.id = pc.component_id
JOIN tradeNamesMap pn
ON pn.product_id = p.id
JOIN tradeNames n
ON n.id = pn.tradeName_id
WHERE
( inci LIKE '%abies%'
OR n.name LIKE '%abies%'
OR 'abies' IN (c.no_cas,c.no_einecs,c.name)
)
AND published = 1
GROUP
BY n.name
ORDER
BY n.name DESC

How to use Group by in mysql

I'm using this sql query to get the product list from DB.
SELECT distinct P.product_id, B.brand_name, P.product_name, P.product_description, SC.sub_category_name, P.product_image_path
FROM table_products as P
INNER JOIN table_brands as B
ON P.brand_id = B.brand_id
INNER JOIN table_product_categories as PC
ON P.product_id = PC.product_id
INNER JOIN table_subcategories as SC
ON SC.sub_categories_id = PC.category_id
INNER JOIN table_subcategory_categories as SCC
ON SC.sub_categories_id = SCC.subcategory_id
ORDER BY P.product_id DESC";
It works fine for me. But when same product is in multiple subcategories. It gives me a new row. I just wanted to avoid this and wants GROUP by with SC.sub_category_name. So when a product is in multiple categories, all the categories should list in same row.
Current
853 Tops Premium Vermicelli /images/tops/853.png Noodles
853 Tops Premium Vermicelli /images/tops/853.png Vermicelli
Expecting
853 Tops Premium Vermicelli /images/tops/853.png Noodles, Vermicelli
You can use GROUP_CONCAT() for that purpose, grouping by SC.sub_category_name and remove the distinct. Something like
SELECT P.product_id,
B.brand_name,
P.product_name,
P.product_description,
GROUP_CONCAT(SC.sub_category_name) as sub_cat_list,
P.product_image_path
FROM table_products P
INNER JOIN table_brands B
ON P.brand_id = B.brand_id
INNER JOIN table_product_categories PC
ON P.product_id = PC.product_id
INNER JOIN table_subcategories SC
ON SC.sub_categories_id = PC.category_id
INNER JOIN table_subcategory_categories SCC
ON SC.sub_categories_id = SCC.subcategory_id
GROUP BY P.product_id
ORDER BY P.product_id DESC;

Unable to count the number of rows returned from query

I have this query
MYSQL:
SELECT COUNT(op.quantity) AS quantity_sold, op.model AS model_number,
op.name AS product_name, ptc.category_id, cd.name
FROM ((`order_product` op INNER JOIN `product` p ON op.product_id = p.product_id)
INNER JOIN (`product_to_category` ptc
INNER JOIN `category_description` cd ON ptc.category_id = cd.category_id) ON op.product_id = ptc.product_id)
INNER JOIN `order` o on o.order_id = op.order_id GROUP BY op.model ORDER BY quantity_sold DESC;
I tried this code to count the no. of rows for the above result.
SELECT COUNT(*) AS total FROM ((`order_product` op INNER JOIN `product` p ON op.product_id = p.product_id)
INNER JOIN (`product_to_category` ptc
INNER JOIN `category_description` cd ON ptc.category_id = cd.category_id) ON op.product_id = ptc.product_id)
INNER JOIN `order` o on o.order_id = op.order_id GROUP BY op.model;
But I am unable to get the count single value.
I need the count of rows returned from the first query as a single value for the purpose of pagination.
If you want the row count that your query returns, wrapping it in an outer query should give you what you want:
SELECT COUNT(*) AS row_count FROM (
SELECT
COUNT(op.quantity) AS quantity_sold,
op.model AS model_number,
op.name AS product_name,
ptc.category_id,
cd.name
FROM order_product op
INNER JOIN product p ON op.product_id = p.product_id
INNER JOIN product_to_category ptc ON op.product_id = ptc.product_id
INNER JOIN category_description cd ON ptc.category_id = cd.category_id
INNER JOIN `order` o on o.order_id = op.order_id
GROUP BY op.model
ORDER BY quantity_sold DESC
) A;