I have a database with the following relationship:
relationship
These tables link a customer to an address:
Cliente = client
Clientenendereco = Many to many table between Endereco (table) and Cliente (table)
Endereco = address
Endereco_rua = address_street
Endereco_cidade = address_city
Endereco_estado = address_state
The cardinality is:
Cliente NxN Endereco
Endereco 1x1 Endereco_rua
Endereco_rua 1x1 Endereco_cidade
Endereco_cidade 1x1 Endereco_state
And the query I use is:
SELECT cli.cliente_id, cli.cliente_cpf, cli.cliente_nome, TIMESTAMPDIFF(YEAR,
cli.cliente_datanasc, CURDATE()) AS idade, ende.endereco_cep, ende.endereco_numero,
ben.beneficio_numero,
ben.beneficio_codigo, ben.beneficio_valor, ban.banco_cod, ab.banco_agencia_numero,
cbb.conta_banco_numero, ben.beneficio_margem_emprestimo, ben.beneficio_margem_cartao
FROM cliente AS cli
RIGHT JOIN telefonencliente AS tnc FORCE INDEX(`fk_telefone_has_cliente_cliente1_idx`)
ON tnc.cliente_id = cli.cliente_id
RIGHT JOIN telefone AS tel
ON tel.telefone_id = tnc.telefone_id
INNER JOIN beneficio AS ben
ON ben.cliente_id = cli.cliente_id
LEFT JOIN clientenendereco AS ce
ON ce.cliente_id = cli.cliente_id
LEFT JOIN endereco AS ende
ON ende.endereco_id = ce.endereco_id
LEFT JOIN endereco_rua AS er
ON er.endereco_rua_id = ende.endereco_rua_id
LEFT JOIN endereco_cidade AS ec
ON ec.endereco_cidade_id = er.cidade_id
LEFT JOIN endereco_estado AS ee
ON ee.endereco_estado_id = ec.estado_id
LEFT JOIN banco_agencia AS ab
ON ab.banco_agencia_id = ben.fk_banco_agencia_id
LEFT JOIN conta_banco AS cbb
ON cbb.conta_banco_id = ben.fk_conta_banco_id
LEFT JOIN banco AS ban
ON ban.banco_id = ben.fk_banco_id
WHERE ee.endereco_estado_id = 1 AND cli.cliente_id IS NOT NULL AND cli.cliente_id NOT
IN(SELECT ci.cliente_id FROM cliente_inativo AS ci WHERE ci.cliente_id = cli.cliente_id)
AND
cli.cliente_id NOT IN (SELECT ma.cliente_id FROM mailing_alocado AS ma WHERE
ma.cliente_id = cli.cliente_id) AND TIMESTAMPDIFF(YEAR, cli.cliente_datanasc,
CURDATE()) >=18 AND TIMESTAMPDIFF(YEAR, cli.cliente_datanasc, CURDATE()) <=68 AND
(ben.beneficio_datainicio BETWEEN '1990-01-01' AND '2007-12-31')
GROUP BY cli.cliente_id
LIMIT 20000
When I use "ee.endereco_estado_id = 1" the query takes 2 minutes to return the records
On the other hand if I remove "ee.endereco_estado_id = 1" the query takes 0.068 seconds
Here with Explain:
With "ee.endereco_estado_id = 1"
Without "ee.endereco_estado_id = 1"
I noticed that without the "ee.endereco_estado_id = 1" It starts with the table "ben", which is good, however, with the "ee.endereco_estado_id = 1" It starts with the table "ee" which takes a long time.
I don't know what to do anymore, because I need the records that are in state number 1, please help me I don't know what I can do or where is my error.
Tables:
endereco ~ 3milions rows
endereco_rua ~ 4milions rows
endereco_cidade ~ 21thousand rows
endereco_estado ~ 26 rows
Let's try turning the query inside out to avoid the GROUP BY, which is probably causing some of the performance hangup.
SELECT ... ((lots of columns))
FROM (
SELECT cliente_id
FROM client
((with the minimal JOINs and WHEREs to get the ids))
ORDER BY .. LIMIT .. -- if needed
) AS ids
JOIN client AS cli ON cli.cliente_id = ids.cliente_id
JOIN (( all the other tables and WHEREs ))
ORDER BY .. -- if needed; note: the inner sort will be lost
I assume you indexes on the various columns in the WHERE clauses? If not, please provide SHOW CREATE TABLE and EXPLAIN SELECT...
Please do not use LEFT when the 'right' table is not optional. Example: ee.endereco_estado_id = 1
Please say which JOINs are 1:1 vs 1:many vs many:1. I need to understand whether the joining "explodes" the number of rows (only to have the GROUP BY implode them). My suggested rewrite assumes that is happening.
Related
I have the query, which is giving correct result, but, I am sure there are other way to do so, having same conditions repeated.
Can anybody help me to reduce the complexity of the query.
Query using these mysql parameters:-
SELECT avai.account_visit_account_info_pk AS Account_ID,
mb.NAME AS Client_Name,
mb.fullname AS Client_Full_Name,
avai.account_name AS Account_Name,
mc.NAME AS Asset_City,
Format(( bfd.finance_value ), 'en_IN') AS Reserve_Price,
Format(( bfd.finance_value ) * 10 / 100, 'en_IN') AS EMD_Value,
Ifnull(Concat(CASE
WHEN mpc.parent = 4 THEN 'Residential'
WHEN mpc.parent = 5 THEN 'Commercial'
WHEN mpc.parent = 6 THEN 'Industrial'
WHEN mpc.parent = 7 THEN 'Agricultural'
END, '/', mpc.category_name), mpc.category_name) Asset_Category,
Concat(ud.first_name, ' ', ud.last_name) AS ADM_Name,
Concat(udd.first_name, ' ', udd.last_name) AS MKT_Name,
mcc.NAME AS ADM_City,
ms.NAME AS ADM_State,
mz.NAME AS ADM_Zone,
bec.e_auction_from AS Auction_Date,
bfdd.finance_value AS Sold_Price
FROM account_branch_visit abv
JOIN mst_product_category mpc
ON mpc.mst_product_category_pk = abv.mst_product_category_pk
JOIN mst_bank mb
ON abv.mst_bank_pk = mb.mst_bank_pk
JOIN banking_financial_details bfd
ON abv.account_branch_visit_pk = bfd.account_branch_visit_pk
AND bfd.mst_financial_pk IN ( 33 )
LEFT JOIN banking_financial_details bfdd
ON abv.account_branch_visit_pk = bfdd.account_branch_visit_pk
AND bfd.mst_financial_pk IN ( 38 )
JOIN mst_city mc
ON mc.mst_city_pk = avai.mst_city_pk
JOIN mst_city mcc
ON mcc.mst_city_pk = avai.mst_city_pk
JOIN mst_state ms
ON ms.mst_state_pk = mcc.mst_state_pk
JOIN mst_zone mz
ON mz.mst_zone_pk = ms.mst_zone_pk
JOIN case_allocation ca
ON ca.account_branch_visit_pk = avai.account_branch_visit_pk
AND ca.mst_activity_pk = 21
JOIN case_allocation caa
ON caa.account_branch_visit_pk = avai.account_branch_visit_pk
AND caa.mst_activity_pk = 18
JOIN user_detail ud
ON ud.user_detail_pk = ca.assignedto
JOIN user_detail udd
ON udd.user_detail_pk = caa.assignedto
JOIN banking_event_calender bec
ON bec.account_branch_visit_pk = avai.account_branch_visit_pk
AND ( abv.closed_reasons_pk IS NULL
OR abv.closed_reasons_pk = 16 )
AND abv.isdeleted = '0'
WHERE avai.account_branch_visit_pk = '1301';
I do not know what the exact intent of the query is, so I will provide some technical nuances, without actually understanding your data model or goal. The select clause provides you some columns and you probably need it. So, what I'm looking for are duplicate table joins. Some of them are necessary, some of them are unnecessary.
banking_financial_details
You join and left join this table with different ideas. You use both of them, so I assume this is necessary.
mst_city
This is obviously unnecessarily duplicating:
JOIN mst_city mc
ON mc.mst_city_pk = avai.mst_city_pk
JOIN mst_city mcc
ON mcc.mst_city_pk = avai.mst_city_pk
Remove the second JOIN and ON clauses from the above and replace all usages of mcc to mc in the query.
case_allocation
You join this table twice, but with different ids and you then join the corresponding user_detail to both and both user_detail instances are being used, so this is probably necessary.
user_detail
Since this duplicated join seems to be used in the select, it's probably necessary.
Summary
We have found an unnecessary join that can be removed. Further shortening of the query may be possible, but we would need to know more about your task and database to determine further improvements.
I have created view which has more than 20 thousand records and executing a query on same view, its taking too long time to fetch only 20 records using limit.
If I removed ORDER BY clause then same query gives result within fraction of sec.
Even I tried that, applied order by condition on view so that I can execute query without ORDER BY clause but still query taking 1.1 min to 1.8 min to return result.
Here is the query :
SELECT full_name, project_no, customer_name, description, status, comments,
FROM (view_project)
WHERE labor_code IS NOT NULL
LIMIT 20
Definition of view :
select a.id AS id,a.tms_id AS tms_id,a.date AS date_from,a.hour AS hour,a.hour_ot AS hour_ot,a.hour_dt AS hour_dt,a.function AS function,a.billable AS billable,a.qb_class AS qb_class,a.comments AS comments,b.extra_fields AS extra_fields,a.labor_code AS labor_code,a.cost AS cost,a.bill AS bill,a.pr_cost AS pr_cost,a.pr_bill AS pr_bill,b.user_id AS user_id,b.date_from AS date_from_b,b.date_to AS date_to,c.full_name AS full_name,c.username AS username,d.name AS name,d.project_no AS project_no,d.id AS project_id,e.description AS description,f.name AS customer_name,concat(b.date_from,'|',b.date_to) AS week_range,a.data_row AS data_row,if((isnull(g.tms_row_status) or (g.tms_row_status = '')),'No Status',g.tms_row_status) AS status,ifnull(h.submit_entity,'') AS submit_entity,a.tms_row_uuid AS tms_row_uuid from (((((((labor_time_tracking a left join timesheet b on((a.tms_id = b.id))) left join user c on((b.user_id = c.id))) left join project d on((a.project_id = d.id))) left join supplier f on((d.customer_id = f.id))) left join item e on((convert(a.labor_code using utf8) = e.uuid))) left join labor_time_tracking_rows g on((a.tms_row_uuid = g.tms_row_uuid))) left join timesheet_submission h on(((a.tms_id = h.tms_id) and (a.project_id = h.project_id) and (a.data_row = h.tms_row_id)))) order by b.id desc
select id from customer_details where store_client_id = 2
And
id NOT IN (select customer_detail_id from orders
where store_client_id = 2 and total_spent > 100 GROUP BY customer_detail_id )
Or
id IN (select tcd.id from property_details as pd, customer_details as tcd
where pd.store_client_id = 2 and pd.customer_detail_id = tcd.customer_id and pd.property_key = 'Accepts Marketing'
and pd.property_value = 'no')
And
id IN (select customer_detail_id from orders
where store_client_id = 2 GROUP BY customer_detail_id HAVING count(customer_detail_id) > 0 )
Or
id IN (select tor.customer_detail_id from ordered_products as top, orders as tor
where tor.id = top.order_id and tor.store_client_id = 2
GROUP BY tor.customer_detail_id having sum(top.price) = 1)`
I have this mysql query with inner join so when it run in mysql server it slow down what is the issue cant find.
But after 4-5 minutes it return 15 000 records. This records is not an issue may be.
In some tutorial suggest to use Inner join, Left join,...
But I don't know how to convert this query in Join clause.
Any help will be appreciated. Thanks in advance.
First of all please read relational model and optimizing select statements.
My Sql query takes more time to execute from mysql database server . There are number of tables are joined with sb_tblproperty table. sb_tblproperty is main table that contain more than 1,00,000 rows . most of table contain 50,000 rows.
How to optimize my sql query to fast execution. I have also used indexing.
indexing Explain - query - structure
SELECT `t1`.`propertyId`, `t1`.`projectId`,
`t1`.`furnised`, `t1`.`ownerID`, `t1`.`subType`,
`t1`.`fors`, `t1`.`size`, `t1`.`unit`,
`t1`.`bedrooms`, `t1`.`address`, `t1`.`dateConfirm`,
`t1`.`dateAdded`, `t1`.`floor`, `t1`.`priceAmount`,
`t1`.`priceRate`, `t1`.`allInclusive`, `t1`.`booking`,
`t1`.`bookingRate`, `t1`.`paidPercetage`,
`t1`.`paidAmount`, `t1`.`is_sold`, `t1`.`remarks`,
`t1`.`status`, `t1`.`confirmedStatus`, `t1`.`source`,
`t1`.`companyName` as company, `t1`.`monthly_rent`,
`t1`.`per_sqft`, `t1`.`lease_duration`,
`t1`.`lease_commencement`, `t1`.`lock_in_period`,
`t1`.`security_deposit`, `t1`.`security_amount`,
`t1`.`total_area_leased`, `t1`.`lease_escalation_amount`,
`t1`.`lease_escalation_years`, `t2`.`propertyTypeName` as
propertyTypeName, `t3`.`propertySubTypeName` subType,
`t3`.`propertySubTypeId` subTypeId, `Owner`.`ContactName`
ownerName, `Owner`.`companyName`, `Owner`.`mobile1`,
`Owner`.`otherPhoneNo`, `Owner`.`mobile2`,
`Owner`.`email`, `Owner`.`address` as caddress,
`Owner`.`contactType`, `P`.`projectName` as project,
`P`.`developerName` as developer, `c`.`name` as city,
if(t1.projectId="", group_concat( distinct( L.locality)),
group_concat( distinct(L2.locality))) as locality, `U`.`firstname`
addedBy, `U1`.`firstname` confirmedBy
FROM `sb_tblproperty` as t1
JOIN `sb_contact` Owner ON `Owner`.`id` = `t1`.`ownerID`
JOIN `tbl_city` C ON `c`.`id` = `t1`.`city`
JOIN `sb_propertytype` t2 ON `t1`.`propertyType`= `t2`.`propertyTypeId`
JOIN `sb_propertysubtype` t3 ON `t1`.`subType` =`t3`.`propertySubTypeId`
LEFT JOIN `sb_tbluser` U ON `t1`.`addedBy` = `U`.`userId`
LEFT JOIN`sb_tbluser` U1 ON `t1`.`confirmedBy` = `U1`.`userId`
LEFT JOIN `sb_tblproject` P ON `P`.`id` = `t1`.`projectId` LEFT
JOIN `sb_tblpropertylocality` PL ON `t1`.`propertyId` = `PL`.`propertyId`
LEFT JOIN `sa_localitiez` L ON `L`.`id` = `PL`.`localityId`
LEFT JOIN `sb_tblprojectlocality` PROL ON `PROL`.`projectId` = `P`.`id`
LEFT JOIN `sa_localitiez` L2 ON `L2`.`id` = `PROL`.`localityId`
LEFT JOIN `sb_tblfloor` F
ON `F`.`floorName` =`t1`.`floor`
WHERE `t1`.`is_sold` != '1' GROUP BY `t1`.`propertyId`
ORDER BY `t1`.`dateConfirm`
DESC LIMIT 1000
Please provide the EXPLAIN.
Meanwhile, try this:
SELECT ...
FROM (
SELECT propertyId
FROM sb_tblproperty
WHERE `is_sold` = 0
ORDER BY `dateConfirm` DESC
LIMIT 1000
) AS x
JOIN `sb_tblproperty` as t1 ON t1.propertyId = x.propertyId
JOIN `sb_contact` Owner ON `Owner`.`id` = `t1`.`ownerID`
JOIN `tbl_city` C ON `c`.`id` = `t1`.`city`
...
LEFT JOIN `sb_tblfloor` F ON `F`.`floorName` =`t1`.`floor`
ORDER BY `t1`.`dateConfirm` DESC -- yes, again
Together with
INDEX(is_sold, dateConfirm)
How can t1.projectId="" ? Isn't projectId the PRIMARY KEY? (This is one of many reasons for needing the SHOW CREATE TABLE.)
If my suggestion leads to "duplicate" rows (that is, multiple rows with the same propertyId), don't simply add back the GROUP BY propertyId. Instead figure out why, and avoid the need for the GROUP BY. (That is probably the performance issue.)
A likely case is the GROUP_CONCAT. A common workaround is to change from
GROUP_CONCAT( distinct( L.locality)) AS Localities,
...
LEFT JOIN `sa_localitiez` L ON `L`.`id` = `PL`.`localityId`
to
( SELECT GROUP_CONCAT(distinct locality)
FROM sa_localitiez
WHERE id = PL.localityId ) AS Localities
...
# and remove the JOIN
I currently have this working using a Sub-query, but as the DB grows this will become HUGELY inefficient. I'm wondering if there is a more efficient way to do what I need to do without sub-queries?
I need to have my final output look like so:
Question, Answer, Responses, Charts included in Response Count
Did this work?, N/A, 26, 30
Did this work?, Yes, 4, 30
This is my current query:
SELECT
bq_text,
ba_a,
bq_id,
COUNT(ba_a) AS ba_aC,
(SELECT COUNT(*) FROM board_done_sheet WHERE sd_b_id = bs.bs_id AND sd_sub = 1) AS sd_chartnumC
FROM board_done_sheet AS sh
LEFT JOIN board_done bd
ON (bd.bd_id = sh.sd_bd_id)
LEFT JOIN boardsubs bs
ON (bd.bd_b_id = bs.bs_id)
LEFT JOIN b_q_answers ba
ON (sh.sd_s_id = ba.ba_s_id)
LEFT JOIN bsquestions bq
ON (bq.bq_id = ba.ba_q_id)
LEFT JOIN multiples m
ON (ba.ba_m_id = m.m_id)
LEFT JOIN users u
ON (u.us_id = bd.bd_d_id)
LEFT JOIN profiles p
ON (p.p_u_id = bd.bd_d_id)
LEFT JOIN users rev
ON (rev.us_id = bd.bd_rev)
WHERE sd_sub = '1' AND bq_text <> 'Date' AND bq_id = 380
GROUP BY bs_id, bq_text, ba_a
That works perfectly, the problem is it has to use sub-queries which as time goes by will get less efficient.
I'm just wondering if there is a better more efficient way to do that summed field without it.
Presumably the subquery you're concerned about is the one in your toplevel SELECT.
That is easy to refactor so it won't get repeated.
Just JOIN it to the rest of the table. You'll want this sort of thing:
SELECT
bq_text, ...
COUNT(ba_a) AS ba_aC,
countup.countup AS sd_chartnumC
FROM board_done_sheet AS sh
LEFT JOIN board_done bd
ON (bd.bd_id = sh.sd_bd_id)
...
LEFT JOIN users rev
ON (rev.us_id = bd.bd_rev)
JOIN (
SELECT COUNT(*) AS countup , sd_b_id
FROM board_done_sheet
WHERE sd_sub = 1
GROUP BY sd_b_id
) AS countup ON countup.sd_b_id = bs.bs_id
WHERE sd_sub = '1'
AND bq_text <> 'Date'
AND bq_id = 380
GROUP BY bs_id, bq_text, ba_a
The countup subquery generates a summary table of counts and ids, and then joins it to the other tables.
A JOIN cascade of this complexity may become inefficient for other reasons as your table grows if you don't structure your indexes correctly.