How to remove range check in query - mysql

I have the following query, when I do an explain for the query it says "Range checked for each record (index map: 0x8)". I am assuming this is one reason the query is as slow, how can I improve this
The query looks as follow currently,
explain select
*
from
(select
CASE WHEN dd.parentId IS NOT NULL
THEN CONCAT(dd.`profileId`,dd.`orgId`,dd.parentId)
ELSE CONCAT(dd.`profileId`,dd.`orgId`,dd.id) END as ticketId,dd.*
from
t_dtls_prod dd where dd.currentlyActive = true and dd.dataSource ='SAND' AND msgCreatedOn BETWEEN '2016-09-01 00:00:00'
AND '2016-10-03 00:00:00' and dd.profileId = 148 group by ticketId ) as d
left join basket_prod b on b.basketId=d.toBasketId
left join lead_social_accts_prod a on a.orgId=1002
AND (
(
(
(a.`type`='TWITTER' and d.channel in (1,34)) or (a.`type`='FACEBOOK' and d.channel in (6,7))
or (a.`type`='GOOGLEPLUS' and d.channel in (5,25)) or (a.`type`='LINKEDIN' and d.channel =30)
or (a.`type`='GOOGLEPLUS' and d.channel=36) or ((a.`type`='YOUTUBE' or a.`type`='GOOGLEPLUS') and d.channel=27)
or (a.`type`='TUMBLR' and d.channel in (29,31)) or
( a.`type`='INSTAGRAM' and d.channel=35)
)
AND
d.userChannelId=a.socialId) OR
(a.`type`='BLOG' and d.channel in (9,11,15,21) AND d.msgId=a.socialId))
left join lead_prod l on l.leadId=a.leadId and l.orgId=1002 where d.profileId = 148 limit 0,1000
The results seem to come out in a descent time upto 1000 rows, but beyond that it just dies.

This should be better
EXPLAIN SELECT
d.*, b.*, a.*, l.*,
(CASE WHEN d.parentId IS NOT NULL
THEN CONCAT(d.`profileId`, d.`orgId`, d.parentId)
ELSE CONCAT(d.`profileId`, d.`orgId`, d.id) END) as ticketId
FROM
t_dtls_prod d
LEFT JOIN basket_prod b ON b.basketId = d.toBasketId
LEFT JOIN lead_social_accts_prod a ON a.orgId = 1002 AND
(
(d.msgId = a.socialId AND d.channel in (9,11,15,21) AND a.`type`='BLOG')
OR
(
d.userChannelId = a.socialId
AND
(
(d.channel IN (1,34) AND a.`type`='TWITTER')
OR
(d.channel IN (6,7) AND a.`type`='FACEBOOK')
OR
(d.channel IN (5, 25, 36) AND a.`type`='GOOGLEPLUS')
OR
(d.channel = 30 AND a.`type`='LINKEDIN')
OR
(d.channel=27 AND a.`type` IN ('YOUTUBE', 'GOOGLEPLUS'))
OR
(d.channel IN (29,31) AND a.`type`='TUMBLR')
OR
(d.channel = 35 AND a.`type`='INSTAGRAM')
)
)
)
LEFT JOIN lead_prod l ON l.leadId = a.leadId AND l.orgId = 1002
WHERE
d.currentlyActive = true AND d.dataSource ='SAND' AND msgCreatedOn BETWEEN '2016-09-01 00:00:00' AND '2016-10-03 00:00:00' AND d.profileId = 148
GROUP BY ticketId
LIMIT 0,1000
LEFT JOIN lead_social_accts_prod a ON a.orgId = 1002 here you forgot connection to t_dtls_prod or basket_prod like a.someId = b.someId

Related

Slow Mysql Inner joins with multiple OR

I'm helping a friend with an e-commerce site. He has options for users to select different colours, styles, use and type of the products he's selling. The query the adds the following to the query:
INNER JOIN tbl_coloursProducts col ON ( p.product_id = col.productID AND (col.colourID = 2 OR col.colourID = 3 OR col.colourID = 5 OR col.colourID = 8 OR col.colourID = 10))
INNER JOIN tbl_useProducts tbluse ON ( p.product_id = tbluse.productID AND (tbluse.useID = 15 OR tbluse.useID = 16 OR tbluse.useID = 17 OR tbluse.useID = 18))
INNER JOIN tbl_styleProducts style ON ( p.product_id = style.productID AND (style.styleID = 39 OR style.styleID = 44))
INNER JOIN tbl_typeProducts type ON ( p.product_id = type.productID AND (type.typeID = 46 OR type.typeID = 48 OR type.typeID = 50))
The query loads fast enough when only a few options are selecting, but some users are selecting multiple or each which is causing the query to run in excess of 30 seconds and timing out.
Without altering the table structure is there a better way to optimise the query?
This is the full query:
SELECT *,
p.product_id,
Coalesce((SELECT p2sp.price
FROM ab_product_specials p2sp
WHERE p2sp.product_id = p.product_id
AND p2sp.customer_group_id = '1'
AND ( ( p2sp.date_start = '0000-00-00'
OR p2sp.date_start < Now() )
AND ( p2sp.date_end = '0000-00-00'
OR p2sp.date_end > Now() ) )
ORDER BY p2sp.priority ASC,
p2sp.price ASC
LIMIT 1), p.price) AS final_price,
pd.name AS name,
m.name AS manufacturer,
ss.name AS stock,
(SELECT Avg(r.rating)
FROM ab_reviews r
WHERE p.product_id = r.product_id
GROUP BY r.product_id) AS rating,
(SELECT Count(rw.review_id)
FROM ab_reviews rw
WHERE p.product_id = rw.product_id
GROUP BY rw.product_id) AS review
FROM ab_products p
LEFT JOIN ab_product_descriptions pd
ON ( p.product_id = pd.product_id
AND pd.language_id = '1' )
LEFT JOIN ab_products_to_stores p2s
ON ( p.product_id = p2s.product_id )
LEFT JOIN ab_manufacturers m
ON ( p.manufacturer_id = m.manufacturer_id )
LEFT JOIN ab_stock_statuses ss
ON ( p.stock_status_id = ss.stock_status_id
AND ss.language_id = '1' )
LEFT JOIN ab_products_to_categories p2c
ON ( p.product_id = p2c.product_id )
INNER JOIN tbl_coloursproducts col
ON ( p.product_id = col.productid
AND ( col.colourid = 2
OR col.colourid = 3
OR col.colourid = 5
OR col.colourid = 8
OR col.colourid = 10 ) )
INNER JOIN tbl_useproducts tbluse
ON ( p.product_id = tbluse.productid
AND ( tbluse.useid = 15
OR tbluse.useid = 16
OR tbluse.useid = 17
OR tbluse.useid = 18 ) )
INNER JOIN tbl_styleproducts style
ON ( p.product_id = style.productid
AND ( style.styleid = 39
OR style.styleid = 44 ) )
INNER JOIN tbl_typeproducts type
ON ( p.product_id = type.productid
AND ( type.typeid = 46
OR type.typeid = 48
OR type.typeid = 50 ) )
WHERE p.status = '1'
AND p.date_available <= Now()
AND p2s.store_id = 0
AND p2c.category_id = 131
GROUP BY p.product_id
ORDER BY p.product_id DESC
LIMIT 0, 8
Without the custom bits the query runs fine.
Looking at that query, not sure the ORs are the problem themselves (although you could possibly make the code more compact by using and IN clause for each one). Rather I suspect that selecting more and more options results in more rows being returned. And this is causing problems with the sub queries in the SELECT clause.
Can you try the query with the sub queries removed from the SELECT clause and see the effect that has.
You can remove the sub queries quite easily.
SELECT *,
p.product_id,
Coalesce(sub1.price, p.price) AS final_price,
pd.name AS name,
m.name AS manufacturer,
ss.name AS stock,
sub0.rating,
sub0.review
FROM ab_products p
INNER JOIN
(
SELECT r.product_id,
Avg(r.rating) AS rating,
Count(rw.review_id) AS review
FROM ab_reviews r
GROUP BY r.product_id
) sub0
ON p.product_id = sub0.product_id
LEFT OUTER JOIN
(
SELECT p2sp.product_id,
SUBSTRING_INDEX(GROUP_CONCAT(p2sp.price ORDER BY p2sp.priority ASC, p2sp.price ASC ), ',', 1) AS price
FROM ab_product_specials p2sp
WHERE p2sp.customer_group_id = '1'
AND ( p2sp.date_start = '0000-00-00' OR p2sp.date_start < NOW() )
AND ( p2sp.date_end = '0000-00-00' OR p2sp.date_end > NOW() )
GROUP BY p2sp.product_id
) sub1
ON p.product_id = sub1.product_id
LEFT JOIN ab_product_descriptions pd
ON ( p.product_id = pd.product_id
AND pd.language_id = '1' )
LEFT JOIN ab_products_to_stores p2s
ON ( p.product_id = p2s.product_id )
LEFT JOIN ab_manufacturers m
ON ( p.manufacturer_id = m.manufacturer_id )
LEFT JOIN ab_stock_statuses ss
ON ( p.stock_status_id = ss.stock_status_id
AND ss.language_id = '1' )
LEFT JOIN ab_products_to_categories p2c
ON ( p.product_id = p2c.product_id )
INNER JOIN tbl_coloursproducts col
ON ( p.product_id = col.productid
AND ( col.colourid = 2
OR col.colourid = 3
OR col.colourid = 5
OR col.colourid = 8
OR col.colourid = 10 ) )
INNER JOIN tbl_useproducts tbluse
ON ( p.product_id = tbluse.productid
AND ( tbluse.useid = 15
OR tbluse.useid = 16
OR tbluse.useid = 17
OR tbluse.useid = 18 ) )
INNER JOIN tbl_styleproducts style
ON ( p.product_id = style.productid
AND ( style.styleid = 39
OR style.styleid = 44 ) )
INNER JOIN tbl_typeproducts type
ON ( p.product_id = type.productid
AND ( type.typeid = 46
OR type.typeid = 48
OR type.typeid = 50 ) )
WHERE p.status = '1'
AND p.date_available <= Now()
AND p2s.store_id = 0
AND p2c.category_id = 131
GROUP BY p.product_id
ORDER BY p.product_id DESC
LIMIT 0, 8
As an aside, when you read from ab_product_specials you are checking for the date_start and date_end to be 0000-00-00 (ie, dates), but also comparing them with NOW() which returns a date / time field. Are those fields date or date / time fields?
My first though was to use IN to make the query eaier to read:
INNER JOIN tbl_coloursProducts col
ON p.product_id = col.productID AND col.colourID IN ( 2, 3, 5, 8, 10 )
Then I thought, I wonder if they are dynamically building SQL text to squirt into the database logic?! The optimizer is unlikely to do well at optimizing queries when they are constantly mutating in this way.
Consider a scratch table (pseudo code):
-- One time:
CREATE TABLE SratchColours ( colourID INT NOT NULL UNQIUE );
-- For each query:
DELETE FROM SratchColours;
INSERT INTO SratchColours VALUES ( 2 ), ( 3 ), ( 5 ), ( 8 ), ( 10 );
Now you dynamic list of values simply becomes just another join:
tbl_coloursProducts NATURAL JOIN SratchColours
(or you could use an inner join if you must!)
Now, having one base table for every concurrent user is probably not a great way to scale a system. Therefore, consider how to pass a bag of colourID values to the database logic (say, a stored proc), put them into a table (say, a temporary table), then join from there to your base tables.

How can I optimize this mysql query having left joins as columns?

This query is taking over 4 seconds to run killing the performance on the page.
The query is doing a sum of points getting the max point by day for a product for a particular month. The purpose is to display a ranking for a given month ordered by the sum of points.
SELECT eriginal_asin, DATE_FORMAT(date_time,'%m/%d/%Y %h:%i:%s') as date_time, SUM(maxpoints) as points, `o1`.`value` as value,
`o2`.`value` as value1, `o3`.`value` as value2, `o4`.`value` as value3, `o5`.`value` as value4, `o6`.`value` as value5,
`o7`.`value` as value6, `o8`.`value` as value7, `o9`.`value` as value8, `o10`.`value` as value9, `o11`.`value` as value10,
`o12`.`value` as value11, `o13`.`value` as value12, `o14`.`value` as value13, `o15`.`value` as value14, `o16`.`value` as value15,
`o17`.`value` as value16, property.id, user.name_surname, user.name_last
from
(SELECT id, eriginal_asin, max(points) as maxpoints, DATE_FORMAT(date_time,'%m/%d/%Y %h:%i:%s') as date_time
from ranking
where date_time >= '2015-09-01'
and date_time <= '2015-09-30 23:59:59'
and points > 0
group by eriginal_asin, region, date(date_time)
)rankmax, property
LEFT JOIN `property_user` ON `property`.`id` = `property_user`.`property_id`
LEFT JOIN `user` ON `property_user`.`user_id` = `user`.`id`
LEFT JOIN `property_value` o1 ON `property`.`id` = `o1`.`property_id` and o1.option_id = 17
LEFT JOIN `property_value` o2 ON `property`.`id` = `o2`.`property_id` and o2.option_id = 10
LEFT JOIN `property_value` o3 ON `property`.`id` = `o3`.`property_id` and o3.option_id = 54
LEFT JOIN `property_value` o4 ON `property`.`id` = `o4`.`property_id` and o4.option_id = 64
LEFT JOIN `property_value` o5 ON `property`.`id` = `o5`.`property_id` and o5.option_id = 65
LEFT JOIN `property_value` o6 ON `property`.`id` = `o6`.`property_id` and o6.option_id = 5
LEFT JOIN `property_value` o7 ON `property`.`id` = `o7`.`property_id` and o7.option_id = 6
LEFT JOIN `property_value` o8 ON `property`.`id` = `o8`.`property_id` and o8.option_id = 10
LEFT JOIN `property_value` o9 ON `property`.`id` = `o9`.`property_id` and o9.option_id = 63
LEFT JOIN `property_value` o10 ON `property`.`id` = `o10`.`property_id` and o10.option_id = 55
LEFT JOIN `property_value` o11 ON `property`.`id` = `o11`.`property_id` and o11.option_id = 56
LEFT JOIN `property_value` o12 ON `property`.`id` = `o12`.`property_id` and o12.option_id = 57
LEFT JOIN `property_value` o13 ON `property`.`id` = `o13`.`property_id` and o13.option_id = 58
LEFT JOIN `property_value` o14 ON `property`.`id` = `o14`.`property_id` and o14.option_id = 59
LEFT JOIN `property_value` o15 ON `property`.`id` = `o15`.`property_id` and o15.option_id = 60
LEFT JOIN `property_value` o16 ON `property`.`id` = `o16`.`property_id` and o16.option_id = 61
LEFT JOIN `property_value` o17 ON `property`.`id` = `o17`.`property_id` and o17.option_id = 62
where property.is_activated = 1
and o1.value = eriginal_asin
GROUP BY DATE(date_time), eriginal_asin
order by points desc
one thing is, you can do it with one LEFT JOIN. I have made a sample (not with all columns) to test if it works better
SELECT eriginal_asin,
DATE_FORMAT(date_time,'%m/%d/%Y %h:%i:%s') AS date_time,
SUM(maxpoints) AS points,
coalesce( IF( o.property_id = 17, `o`.`value`, NULL )) AS value_1,
coalesce(IF (o.property_id = 10, `o`.`value`, NULL )) AS value_
coalesce(IF (o.property_id = 54, `o`.`value`, NULL )) AS value_3,
coalesce(IF (o.property_id = 64, `o`.`value`, NULL )) AS value_4,
property.id,
user.name_surname,
user.name_last
FROM
(SELECT id,
eriginal_asin,
max(points) AS maxpoints,
DATE_FORMAT(date_time,'%m/%d/%Y %h:%i:%s') AS date_time
FROM ranking
WHERE date_time >= '2015-09-01'
AND date_time <= '2015-09-30 23:59:59'
AND points > 0
GROUP BY eriginal_asin,
region,
date(date_time) )rankmax,
property
LEFT JOIN `property_user` ON `property`.`id` = `property_user`.`property_id`
LEFT JOIN `user` ON `property_user`.`user_id` = `user`.`id`
LEFT JOIN `property_value` o ON `property`.`id` = `o`.`property_id`
WHERE property.is_activated = 1
AND o1.value = eriginal_asin
GROUP BY o.property_id,
DATE(date_time),
eriginal_asin
ORDER BY points DESC;
A few things... Can you please provide some sample data of your "Property_Value" table records... what are the "values". Ranking.ID... Is that the ID associated to the property? You have no join condition to that and THAT may be causing a Cartesian result.
Does the Ranking table have a "Property_ID" column to join against. Do you have index on your property_value table on ( value, id, option_id )... A combination/multi-field index would significantly help too.
Also, it is unclear exactly how / where the property ID is based on the RankMax table -- or does the property table have the "eriginal_asin" column (doubt it).
Existing table structures and some sample data (space formatting of data instead of tabs preferred) would help myself and/or others to helping you out.
EXAMPLE ONLY OF DATA (you can copy/paste in your original question and adjust content as needed), but your join criteria really is missing somewhere.
Property Table
ID Is_Activiated OtherDescript
1 1 Test Sample
2 0 Another Property
3 1 last
User Table
ID UserName
PropertyUser Table
ID Property_ID
1 3
2 1
3 2
Property_value table
ID Property_ID Option_ID Value
1 3 17 blah
1 3 10 another
1 3 54 blah 2

MySQL: Grouped by hour, need to show all hours, null where no data

Here's the query:
SELECT h.idhour, h.`hour`, outnumber, count(*) as `count`, sum(talktime) as `duration`
FROM (
SELECT
`cdrs`.`dcustomer` AS `dcustomer`,
(CASE
WHEN (`cdrs`.`cnumber` like "02%") THEN '02'
WHEN (`cdrs`.`cnumber` like "05%") THEN '05'
END) AS `outnumber`,
FROM_UNIXTIME(`cdrs`.`start`) AS `start`,
(`cdrs`.`end` - `cdrs`.`start`) AS `duration`,
`cdrs`.`talktime` AS `talktime`
FROM `cdrs`
WHERE `cdrs`.`start` >= #_START and `cdrs`.`start` < #_END
AND `cdrs`.`dtype` = _LATIN1'external'
GROUP BY callid
) cdr
JOIN customers c ON c.id = cdr.dcustomer
LEFT JOIN hub.hours h ON HOUR(cdr.`start`) = h.idhour
WHERE (c.parent = _ID or cdr.dcustomer = _ID or c.parent IN
(SELECT id FROM customers WHERE parent = _ID))
GROUP BY h.idhour, cdr.outnumber
ORDER BY h.idhour;
The above query results skips the hours where there is no data, but I need to show all hours (00:00 to 23:00) with null or 0 values. How can I do this?
SELECT h.idhour
, h.hour
,IFNULL(outnumber,'') AS outnumber
,IFNULL(cdr2.duration,0) AS duration
,IFNULL(output_count,0) AS output_count
FROM hub.hours h
LEFT JOIN (
SELECT HOUR(start) AS start,outnumber, SUM(talktime) as duration ,COUNT(1) AS output_count
FROM
(
SELECT cdrs.dcustomer AS dcustomer
, (CASE WHEN (cdrs.cnumber like "02%") THEN '02' WHEN (cdrs.cnumber like "05%") THEN '05' END) AS outnumber
, FROM_UNIXTIME(cdrs.start) AS start
, (cdrs.end - cdrs.start) AS duration
, cdrs.talktime AS talktime
FROM cdrs cdrs
INNER JOIN customers c ON c.id = cdrs.dcustomer
WHERE cdrs.start >= #_START and cdrs.start < #_END AND cdrs.dtype = _LATIN1'external'
AND
(c.parent = _ID or cdrs.dcustomer = _ID or c.parent IN (SELECT id FROM customers WHERE parent = _ID))
GROUP BY callid
) cdr
GROUP BY HOUR(start),outnumber
) cdr2
ON cdr2.start = h.idhour
ORDER BY h.idhour
You need a table with all hours, nothing else.
Then use LEFT JOIN with the hours table on the "left" and your current query on the "right":
SELECT b.*
FROM hours h
LEFT JOIN ( ... ) b ON b.hr = h.hr
WHERE h.hr BETWEEN ... AND ...
ORDER BY hr;
Any missing hours will be NULLs in b.*.

How to optimize for speed a sql multiple select with SUM

I have a really long select from my database with many joins. The problem is with counting SUM: without sum, select time is about 3s, but with SUM is about 15s.
Is it possible to optimize my select to obtain a shorter select time?
Here is my code:
SELECT
accomodation.id,
accomodation.aid,
accomodation.title_en,
accomodation.title_url_en,
accomodation.address,
accomodation.zip,
accomodation.stars,
accomodation.picture,
accomodation.valid_from,
accomodation.valid_to,
accomodation.latitude,
accomodation.longitude,
accomodation.city_id AS
accomodation_city_id,
db_cities.id AS city_id,
db_cities.title_en AS city,
db_cities.title_url AS city_url,
db_countries.title_en AS country_title,
db_countries.title_url_en AS country_url,
accomodation_type.class AS accomodation_type_class,
accomodation_review_value_total.value AS review_total,
MIN(accomodation_price.price) AS price_from,
accomodation_rooms.total_persons
FROM
(SELECT aid, MAX(info_date_add) AS max_info_date_add FROM accomodation GROUP BY aid) accomodation_max
INNER JOIN accomodation
ON
accomodation_max.aid = accomodation.aid AND
accomodation_max.max_info_date_add = accomodation.info_date_add
LEFT JOIN db_cities
ON (
db_cities.id = accomodation.city_id OR
(((acos(sin((db_cities.latitude*pi()/180)) * sin((accomodation.latitude*pi()/180)) + cos((db_cities.latitude*pi()/180)) * cos((accomodation.latitude*pi()/180)) * cos(((db_cities.longitude - accomodation.longitude)*pi()/180))))*180/pi())*60*1.1515*1.609344) < '20')
JOIN db_countries
ON db_countries.id = accomodation.country_id
LEFT JOIN accomodation_review_value_total
ON accomodation_review_value_total.accomodation_aid = accomodation.aid
LEFT JOIN accomodation_type_value
ON accomodation_type_value.accomodation_id = accomodation.id
LEFT JOIN accomodation_type
ON accomodation_type.id = accomodation_type_value.accomodation_type_id
JOIN accomodation_season
ON (
accomodation_season.accomodation_aid = accomodation.aid AND
( '2013-11-04' BETWEEN accomodation_season.start_date AND accomodation_season.end_date OR '2013-11-05' BETWEEN accomodation_season.start_date AND accomodation_season.end_date ) )
JOIN accomodation_price
ON
accomodation_price.accomodation_aid = accomodation.aid AND
accomodation_price.accomodation_price_type_id = '1' AND
accomodation_price.accomodation_price_cat_id = '1' AND
accomodation_price.price BETWEEN '20' AND '250' AND
accomodation_price.accomodation_season_id = accomodation_season.id
JOIN accomodation_theme_value
ON accomodation_theme_value.accomodation_id = accomodation.id
INNER JOIN
(SELECT
accomodation_id,
SUM(accomodation_rooms.rooms) AS total_rooms,
SUM(accomodation_rooms.beds * accomodation_rooms.rooms) AS total_persons
FROM accomodation_rooms
GROUP BY accomodation_id) accomodation_rooms
ON
accomodation_rooms.accomodation_id = accomodation.id AND
accomodation_rooms.total_persons >= '4'
WHERE
db_countries.title_url_en LIKE '%spain%' AND
db_cities.title_url LIKE '%barcelona%' AND
accomodation_type_value.accomodation_type_id IN (5,10) AND
total_rooms >= '2' AND
accomodation_theme_value.accomodation_theme_id IN (11,12,13) AND
accomodation.stars IN (3,4,5) AND
( accomodation_review_value_total.value >= '4.5' ) AND
db_cities.id = '2416'
GROUP BY accomodation.aid
ORDER BY
CASE
WHEN accomodation.valid_to>=NOW() AND accomodation.valid_from<=NOW() AND MIN(accomodation_price.price) IS NOT NULL THEN 0
WHEN NOW()>accomodation.valid_to AND accomodation.valid_to>'0000-00-00' AND MIN(accomodation_price.price) IS NOT NULL THEN 1
WHEN accomodation.valid_to>=NOW() AND accomodation.valid_from<=NOW() THEN 2
WHEN NOW()>accomodation.valid_to AND accomodation.valid_to>'0000-00-00' THEN 3
ELSE 4 END,
review_total DESC,
accomodation.title_en
LIMIT 10

MySQL Join Optimization

Can you please help me optimize this query. I use this query to get a list of friends along with their details and their status.
It takes about 0.08 secs to process this on a Athlon X2 6000
I cant use materizlized view as well because this is frequently changing.
SELECT p.userid, p.firstname, p.lastname, p.gender, p.dob, x.relationship,
IF(p.picture !=1,
IF(p.gender != 'm','/sc/f-t.jpg','/sc/m-t.jpg'),
concat('/sc/pthumb/', p.userid, '.jpg' )) AS picture
FROM `social` AS p
LEFT JOIN `friendlist` AS f1 ON (f1.`userid` = p.`userid` AND f1.`friendid` = 1 AND `f1`.`status` = 1)
LEFT JOIN `friendlist` AS f2 ON (f2.`friendid` = p.`userid` AND f2.`userid` = 1 AND `f2`.`status` = 1)
LEFT JOIN `x_relationship` AS x ON (x.`id` = p.`relationship`)
LEFT JOIN `auth` as a ON (a.`userid` = p.`userid`)
WHERE 1 AND (f1.`userid` IS NOT NULL OR f2.`userid` IS NOT NULL AND ((a.`banned` != 1 AND a.`deleted` != 1)))
ORDER BY RAND() LIMIT 0,10
This is your original query, formatted. Below it are a few thoughts.
SELECT
p.userid,
p.firstname,
p.lastname,
p.gender,
p.dob,
x.relationship,
IF(p.picture !=1, IF(p.gender != 'm', '/sc/f-t.jpg', '/sc/m-t.jpg'), concat('/sc/pthumb/', p.userid, '.jpg' )) AS picture
FROM
`social` AS p
LEFT JOIN `friendlist` AS f1 ON (f1.`friendid` = 1 AND f1.`userid` = p.`userid` AND `f1`.`status` = 1)
LEFT JOIN `friendlist` AS f2 ON (f2.`friendid` = p.`userid` AND f2.`userid` = 1 AND `f2`.`status` = 1)
LEFT JOIN `x_relationship` AS x ON (x.`id` = p.`relationship`)
LEFT JOIN `auth` AS a ON (a.`userid` = p.`userid`)
WHERE
1
AND (
f1.`userid` IS NOT NULL
OR f2.`userid` IS NOT NULL
AND (a.`banned` != 1 AND a.`deleted` != 1)
)
ORDER BY
RAND()
LIMIT
0,10
Think if some of your left joins could be inner joins. If so, change them.
Your WHERE clause is messed up. You are mixing AND and OR without properly prioritizing with parentheses. Try:
WHERE
a.`banned` != 1
AND a.`deleted` != 1
AND (
f1.`userid` IS NOT NULL
OR f2.`userid` IS NOT NULL
)
You could also try:
INNER JOIN `auth` AS a ON (
a.`userid` = p.`userid`
AND a.`banned` != 1
AND a.`deleted` != 1
)
WHERE
f1.`userid` IS NOT NULL
OR f2.`userid` IS NOT NULL
You seem to be joining against friendlist solely to check for record existence. You might want to give this a try as well:
FROM
`social` AS p
INNER JOIN `auth` AS a ON (
a.`userid` = p.`userid`
AND a.`banned` != 1
AND a.`deleted` != 1
)
LEFT JOIN `x_relationship` AS x ON (
x.`id` = p.`relationship`
)
WHERE
EXISTS (
SELECT 1 FROM `friendlist` WHERE `friendid` = 1 AND `userid` = p.`userid` AND `status` = 1
)
OR EXISTS (
SELECT 1 FROM `friendlist` WHERE `friendid` = p.`userid` AND `userid` = 1 AND `status` = 1
)
ORDER BY RAND() might not be the fastest thing on earth, but if this is what you need... Try ordering by a indexed column to see how much impact ORDER BY RAND() has.
Indexing:
You should create a composite index on friendlist(friendid, userid, status).
Make sure there is an index on relationship(id)
Make sure there is an index on auth(userid)