Optimize select mysql - mysql

can help me to optimize this query?
Thanks for your support
SELECT cs_annunci.ID, cs_utenti.ID, cs_annunci.Data, cs_annunci.Tipologia,
cs_annunci.Foto1, cs_annunci.Titolo, cs_annunci.IDRazza,
cs_annunci.Cucciolo, cs_utenti.Attivita, cs_annunci.IDRubrica,
cs_annunci.IDSottorubrica, cs_annunci.Position, cs_annunci.Ora,
cs_annunci.Prezzo, cs_annunci.Pedigree, cs_annunci.IDProvincia
FROM cs_annunci, cs_utenti, cs_regioni
WHERE cs_annunci.IDUtente = cs_utenti.ID
AND cs_annunci.IDRegione = cs_regioni.ID
AND cs_utenti.Sospeso = '0'
AND cs_annunci.Attiva = '1'
AND cs_utenti.Cancellato = '0'
ORDER BY cs_annunci.Position DESC, cs_annunci.Data DESC,
cs_annunci.Ora DESC
LIMIT 0, 20
EXPLAIN (.png)

As an aside, I find this easier to read...
SELECT a.ID
, u.ID
, a.Data
, a.Tipologia
, a.Foto1
, a.Titolo
, a.IDRazza
, a.Cucciolo
, u.Attivita
, a.IDRubrica
, a.IDSottorubrica
, a.Position
, a.Ora
, a.Prezzo
, a.Pedigree
, a.IDProvincia
FROM cs_annunci a
JOIN cs_utenti u
ON u.ID = a.IDUtente
JOIN cs_regioni r
ON r.ID = a.IDRegione
WHERE u.Sospeso = 0
AND a.Attiva = 1
AND u.Cancellato = 0
ORDER
BY a.Position DESC
, a.Data DESC
, a.Ora DESC
LIMIT 0, 20

This index is likely to helps with the speed:
INDEX(Attiva, Position, Data, Ora)
in exactly that order.
The query does not seem to be using cs_regioni except for verifying that a row exists; remove references to that table if possible.
Index Cookbook .
If you need to discuss this further, please provide SHOW CREATE TABLE so we can know the datatypes, indexes, and engines involved.

Related

I want to improve the speed of query statements, but I want to know how

When executing a query statement, the speed is very slow.
SELECT
T1.APPL_SEQ
, T1.COMP_CD
, (SELECT COMP_NM FROM tb_company WHERE COMP_CD = T1.COMP_CD) AS COMP_NM
, T1.GPROD_CD
, (SELECT GPROD_NM FROM tb_gprod WHERE GPROD_CD = T1.GPROD_CD) AS GPROD_NM
, T1.SITE_CD
, (SELECT SITE_NM FROM tb_site WHERE SITE_CD = T1.SITE_CD) AS SITE_NM
, T1.INFLOW_CD
, T1.INFLOW_URL
, T1.STATUS
, T1.REG_DTM
, DECRYPTO(T1.NAME) AS NAME
, DECRYPTO(T1.HP) AS HP
, ifnull(T1.AGE,T1.`115`) AS AGE
, ifnull(T1.GENDER,T1.`116`) AS GENDER
, ifnull(T1.MEMO,T1.`120`) AS MEMO
, ifnull(T1.`105`,T1.`124`) AS TIME
, T1.`125` AS AGE_CHILD
, T2.API_YN
, T2.API_START_DT
, T2.API_END_DT
, T2.API_CD
, T2.DATA_INFLOWCD
, T2.CONFIRM_YN
, T2.SALE_YN
, T2.SALE_PRICE
, T2.BREAKDOWN
, T2.INPUT_DATE
, T3.DIST_YN
, T3.DIST_DT
,(select ifnull((select timestampdiff(DAY, T11.REG_DTM,T1.REG_DTM) AS DIFF2REGTIME from tb_applicant T11 WHERE T11.HP = T1.HP AND T11.GPROD_CD = T1.GPROD_CD AND T11.REG_DTM < T1.REG_DTM order by T11.REG_DTM desc limit 1),-1)) AS HP2_COUNT
FROM
tb_applicant T1
LEFT JOIN mm_applicant T2
ON T1.APPL_SEQ = T2.APPL_SEQ
LEFT JOIN dist_applicant T3
ON T1.APPL_SEQ = T3.APPL_SEQ
LEFT JOIN tb_site T4
ON T4.site_cd = T1.SITE_CD and T4.comp_cd = T1.COMP_CD and T4.gprod_cd = T1.GPROD_CD
WHERE 1=1
AND T1.APPL_SEQ > 147293
AND T4.is_use = 'Y'
$Sql_Search
ORDER BY
$Sql_OrderBy
) U1
, (SELECT #ROWNUM := 0) U2
) V1";
,(select ifnull((...),-1)) AS HP2_COUNT
This is part of why it's so slow.
This query calculates the number of months difference by comparing REG_DTM when the td_applicant table has the same data for HP, GPROD, and COMP.
I don't need to get the date difference, is there any way to improve the query speed?
The main problem are those subselect in the select. As #Akina suggested, you should move them in FROM and make them as join.
They way you have done implies that each subselect is executed for each row returned by the main select.
You have 4 subselect that mean if you have 100 rows you execute 1 (main select) + (4*100) query so 401 instead of 1.
Using join allow the internal optimization engine to choose the best strategy to perform the query, in your way practically no optimization are applied.
I post a short example of how should be your query, didn't refactor the whole query since without database is a bit difficult to do it and I can easily produce a wrong query.
Notice that you select twice on tb_site with different condition, so is up to you to put the correct one.
SELECT T1.APPL_SEQ, T1.COMP_CD, T1.GPROD_CD, T1.SITE_CD
TC.COMP_NM,
TG.GPROD_NM,
TS.SITE_NM,
......
FROM tb_applicant T1
LEFT JOIN mm_applicant T2
JOIN tb_company TC on TC.COMP_CD = T1.COMP_CD
JOIN tb_gprod TG on GPROD_CD = T1.GPROD_CD
JOIN tb_site TS on TS.SITE_CD = T1.SITE_CD ON T1.APPL_SEQ = T2.APPL_SEQ
.......

MySQL Join returns too many rows with WHERE clause

I am having trouble with a SQL query. So in my project user can reserve a ride. I want to display reserved rides by users ID (passenger_id) but query returns all users (driver_id) advertisements when user reserved a ride only for one of drivers advertisements.
SELECT advertisement.id
, COUNT(review.driver_id) AS 'review_count'
, ROUND(AVG(review.mark) ,1) AS 'rating'
, users.unique_id
, users.name
, users.surname
, users.phone
, YEAR(CURDATE()) - YEAR(users.birthdate) AS age
, users.image
, advertisement.from_city
, advertisement.to_city
, users.car_name
, users.car_model
, users.car_make_year
, advertisement.number_of_places
, advertisement.price
, advertisement.datetime
, advertisement.info
FROM reserved_rides
JOIN advertisement
ON reserved_rides.driver_id = advertisement.user_id
LEFT
JOIN review
ON reserved_rides.driver_id = review.driver_id
JOIN users
ON reserved_rides.driver_id = users.unique_id
WHERE reserved_rides.passenger_id = ?
GROUP
BY advertisement.id
ORDER
BY advertisement.datetime ASC
What is going wrong here?
I hope replacing GROUP BY advertisement.id with GROUP BY reserved_rides.driver_idsolves your problem. cheers

query taking long time to execute and crashing the site

I am having around 2.5 lachs (250K) products and 2600 subcategories on magento application (community edition).
Query
SELECT 1 status
, e.entity_id
, e.type_id
, e.attribute_set_id
, cat_index.position AS cat_index_position
, e.name
, e.description
, e.short_description
, e.price
, e.special_price
, e.special_from_date
, e.special_to_date
, e.cost
, e.small_image
, e.thumbnail
, e.color
, e.color_value
, e.news_from_date
, e.news_to_date
, e.url_key
, e.required_options
, e.image_label
, e.small_image_label
, e.thumbnail_label
, e.msrp_enabled
, e.msrp_display_actual_price_type
, e.msrp
, e.tax_class_id
, e.price_type
, e.weight_type
, e.price_view
, e.shipment_type
, e.links_purchased_separately
, e.links_exist
, e.open_amount_min
, e.open_amount_max
, e.custom_h1
, e.awards
, e.region
, e.grape_type
, e.food_match
, e.udropship_vendor
, e.upc_barcode
, e.ean_barcode
, e.mpn
, e.size
, e.author
, e.format
, e.pagination
, e.publish_date
, price_index.price
, price_index.tax_class_id
, price_index.final_price
, IF(price_index.tier_price IS NOT NULL
, LEAST(price_index.min_price
, price_index.tier_price)
, price_index.min_price) AS minimal_price
, price_index.min_price
, price_index.max_price
, price_index.tier_price
FROM catalog_product_flat_1 e
JOIN catalog_category_product_index cat_index
ON cat_index.product_id = e.entity_id
AND cat_index.store_id = 1
AND cat_index.visibility IN(2,4)
AND cat_index.category_id = 163
JOIN catalog_product_index_price price_index
ON price_index.entity_id = e.entity_id
AND price_index.website_id = 1
AND price_index.customer_group_id = 0
GROUP
BY e.entity_id
ORDER
BY cat_index_position ASC
, cat_index.position ASC
LIMIT 15;
whenever accessing any products on this magento site it created a huge data under /tmp directory on theserver which is around 10 GB.
How can I fix this please suggest some solution.
Database size is 50 GB and server is nginx.
You are misusing GROUP BY. Please learn how it works. There's a misfeature in MySQL which allows you to misuse it. Unfortunately, queries that misuse it are very difficult to troubleshoot.
It is difficult to infer what you are trying to do from your query. When you're dealing with result sets of that size, it helps to know your intent.
You should know, if you don't already, that queries of the form
SELECT <<many columns>>
FROM large_table
JOIN another_large_table ON something
JOIN another_large_table ON something
ORDER BY some_arbitrary_column
LIMIT some_small_number
can be grossly inefficient because they have to generate an enormous result set, then sort the whole thing, then return the first results. The sort operation carries the whole result set with it. You could be instructing the MySQL server to sort a crore or two of rows (dozens of megarows).
It looks like you want the first fifteen results starting with the lowest cat_index.position value. Accordingly, you may be able to make your query faster by joining with an appropriate subset of the table you call cat_index, like so:
SELECT 1 status, many_other_columns
FROM catalog_product_flat_1 e
JOIN ( /* join only with fifteen lowest eligible position values in cat_index */
SELECT *
FROM catalog_category_product_index
WHERE store_id = 1
AND visibility IN(2,4)
AND category_id = 163
ORDER BY position ASC
LIMIT 15
) AS cat_index ON cat_index.product_id = e.entity_id
JOIN catalog_product_index_price price_index
ON price_index.entity_id = e.entity_id
AND price_index.website_id = 1
AND price_index.customer_group_id = 0
GROUP BY e.entity_id /*wrong!!*/
ORDER BY cat_index_position ASC, /* redundant!*/
cat_index.position ASC
LIMIT 15;
It's worth a try.
Are you have sufficient Hardware resources to run a big query and also please update you hardware configuration of server.

Sql query to show only most recent message for specific user?

I have two sql tables one which has users and the other which has messages.
Right now my query is :
SELECT users.memberid,users.username,users.profileimage,users.gender,message.messagebody, message.fromid,message.toid,message.messageid
FROM message,users
WHERE message.fromid = users.memberid AND message.toid = '$id' AND recieverdeleted='0'
ORDER BY datetime DESC LIMIT 55
Right now what is being returned is all the information for everymessage regardless of formid(sender's id)
The thing is , I want to only display the most recent message for every from id ..Kind of like how Facebook only shows you the most recent message that friend x has sent you, and not all the messages. I will work on showing all messages after the user has clicked on his friend's most recent message.
Thanks
Well, you tried. That's good.
SELECT u.memberid
, u.username
, u.profileimage
, u.gender
, m.messagebody
, m.fromid
, m.toid
, m.messageid
FROM users u
JOIN message m
ON m.fromid = u.memberid
JOIN (SELECT fromid,toid,MAX(datetime) max_datetime FROM message GROUP BY fromid,toid) n
ON n.fromid = m.fromid
AND n.toid = m.toid
AND n.max_datetime = m.datetime
WHERE message.toid = $id
AND recieverdeleted = 0
ORDER
BY datetime DESC LIMIT 55;
At first join the two tables than apply order by because at this moment the command is not sure for which table you want to apply the ordering.
Or better you create an intermediate table from the selection of two tables and then apply the ordering.
Something like:
SELECT username,messagebody,fromid FROM(
SELECT users.memberid,users.username,users.profileimage,users.gender,message.messagebody, message.fromid,message.toid,message.messageid,message.datetime
FROM message,users
WHERE message.fromid = users.memberid AND message.toid = '$id' AND recieverdeleted='0' )INTERMEDIATE_TABLE ORDER BY datetime DESC
I might be wrong in syntax as I have done sql codes a long ago but you should try something very similar like this.
Try this its working
SELECT m1.*
FROM table_name m1
INNER JOIN (SELECT MAX(senddate) AS senddate,
IF(member_id2 = 3, member_id1, member_id2 ) AS user
FROM table_name
WHERE (member_id1 = 3 AND delete1=0) OR
(member_id2 = 3 AND delete2=0)
GROUP BY user) m2
ON m1.senddate = m2.senddate AND
(m1.member_id1 = m2.user OR m1.member_id2 = m2.user)
WHERE (member_id1 = 3 AND delete1=0) OR
(member_id2 = 3 AND delete2=0)
ORDER BY m1.senddate DESC
Try this::
SELECT users.memberid,users.username,users.profileimage,users.gender,message.messagebody, message.fromid,message.toid,message.messageid
FROM message inner join users on (message.fromid = users.memberid)
where message.toid = '$id' AND recieverdeleted='0'
ORDER BY message_datetime DESC limit 1

mysql where condition priority

I have the following query and it gets the first result "Edit: of each contact" as I want but I do not need any other results per contact after. So example if they have 3 phone # and one is main, it gives me the main then the other 2. I have tried grouping but it ends up getting the first one pulled no matter if main or not. Any thoughts to how I could do this without doing a php check in the loop for if contact already exists?
SELECT pc.firstname, pc.lastname, pp.areacode, pp.prefix, pp.last4
, if(pc.mainphone = pp.phoneid,1,0) as phone_priority
FROM contacts pc
JOIN phone pp ON ( (pp.contid = pc.contid && pp.phoneid = pc.mainphone) || (pp.contid = pc.contid) )
ORDER BY pc.lastname ASC, pc.firstname ASC, phone_priority DESC
Table setup:
contacts (id, firstname, lastname, mainphone)
phone (id, areacode, prefix, last4)
Using MySQL 4.
Use a LIMIT expression to narrow the result set down to the first result. See SELECT Syntax for details.
Use LIMIT 1 at the end of your query
Use a left join:
SELECT pc.firstname,
pc.lastname,
pp.areacode,
pp.prefix,
pp.last4 ,
CASE
WHEN pp.mainphone IS NULL THEN 0
ELSE 1
END AS phone_priority
FROM contacts pc LEFT JOIN phone pp
ON pp.contid = pc.contid
AND pp.phoneid = pc.mainphone
ORDER BY pc.lastname ASC, pc.firstname ASC, phone_priority DESC
Try this variant -
SELECT t.contid
, t.firstname
, t.lastname
, if(t.phoneid IS NULL, p2.phoneid, t.phoneid) phone
, if(t.phoneid IS NULL, p2.areacode, t.areacode) areacode
, if(t.phoneid IS NULL, p2.prefix, t.prefix) prefix
, if(t.phoneid IS NULL, p2.last4, t.last4) last4
FROM
(
SELECT c.contid
, c.firstname
, c.lastname
, c.mainphone
, p.phoneid
, p.areacode
, p.prefix
, p.last4
FROM
contacts c
LEFT JOIN phone p
ON c.contid = p.contid AND c.mainphone = p.phoneid) t
LEFT JOIN phone p2
ON t.contid = p2.contid AND t.mainphone <> p2.phoneid
GROUP BY
t.contid