Improve query performance from many Master table - mysql

I have a query. I have created index for all joined key, pre-filter the master table and choose specific rows to select, but it still take long time to show(sometimes it hangs). What should We do to improve the performance?
SELECT *
FROM t_responden a
INNER JOIN t_kepemilikan_tik b
ON a.res_id = b.res_id
INNER JOIN t_televisi c
ON a.res_id = c.res_id
INNER JOIN t_telepon_hp d
ON a.res_id = d.res_id
INNER JOIN t_radio e
ON a.res_id = e.res_id
INNER JOIN t_media_cetak f
ON a.res_id = f.res_id
INNER JOIN t_internet g
ON a.res_id = g.res_id
LEFT JOIN t_mst_pendidikan n
ON a.res_pendidikan_kk = n.kd_pendidikan
LEFT JOIN t_mst_pendidikan o
ON a.res_pendidikan = o.kd_pendidikan
LEFT JOIN t_mst_penghasilan p
ON a.res_penghasilan = p.kd_penghasilan
LEFT JOIN t_mst_aksesibilitas q
ON a.res_aksesibilitas = q.kd_akses
LEFT JOIN t_mst_mobilitas r
ON a.res_mobilitas = r.kd_mobilitas
LEFT JOIN t_mst_pekerjaan s
ON a.res_pekerjaan = s.kode
LEFT JOIN t_mst_pengeluaran t
ON a.res_pengeluaran = t.kode
INNER JOIN t_pernyataan h
ON a.res_id = h.res_id
INNER JOIN (SELECT * FROM t_mst_prop WHERE kode IN ( '3200', '1600', '1800', '3600' )) i
ON a.res_propinsi = i.kode
INNER JOIN (SELECT * FROM t_mst_kabkota WHERE kode_prop IN ( '3200', '1600', '1800', '3600' )) j
ON ( a.res_kabkota = j.kode
AND a.res_propinsi = j.kode_prop )
INNER JOIN (SELECT * FROM t_mst_kec WHERE kode_prop IN ( '3200', '1600', '1800', '3600' )) k
ON ( a.res_kecamatan = k.kode
AND a.res_kabkota = k.kode_kabkota
AND a.res_propinsi = k.kode_prop )
INNER JOIN (SELECT * FROM t_mst_desa WHERE kode_prop IN ( '3200', '1600', '1800', '3600' ))l
ON ( a.res_keldesa = l.kode
AND a.res_kabkota = l.kode_kabkota
AND a.res_propinsi = l.kode_prop
AND l.kode_kec = a.res_kecamatan )
WHERE a.res_tahunsurvei = 2013
AND res_propinsi IN ( '3200', '1600', '1800', '3600' )
ORDER BY 1

SELECT STRAIGHT_JOIN
*
FROM
t_responden a
INNER JOIN t_kepemilikan_tik b
ON a.res_id = b.res_id
INNER JOIN t_televisi c
ON a.res_id = c.res_id
INNER JOIN t_telepon_hp d
ON a.res_id = d.res_id
INNER JOIN t_radio e
ON a.res_id = e.res_id
INNER JOIN t_media_cetak f
ON a.res_id = f.res_id
INNER JOIN t_internet g
ON a.res_id = g.res_id
LEFT JOIN t_mst_pendidikan n
ON a.res_pendidikan_kk = n.kd_pendidikan
LEFT JOIN t_mst_pendidikan o
ON a.res_pendidikan = o.kd_pendidikan
LEFT JOIN t_mst_penghasilan p
ON a.res_penghasilan = p.kd_penghasilan
LEFT JOIN t_mst_aksesibilitas q
ON a.res_aksesibilitas = q.kd_akses
LEFT JOIN t_mst_mobilitas r
ON a.res_mobilitas = r.kd_mobilitas
LEFT JOIN t_mst_pekerjaan s
ON a.res_pekerjaan = s.kode
LEFT JOIN t_mst_pengeluaran t
ON a.res_pengeluaran = t.kode
INNER JOIN t_pernyataan h
ON a.res_id = h.res_id
INNER JOIN t_mst_prop i
ON a.res_propinsi = i.kode
INNER JOIN t_mst_kabkota j
ON a.res_propinsi = j.kode_prop
AND a.res_kabkota = j.kode
INNER JOIN t_mst_kec k
ON a.res_propinsi = k.kode_prop
AND a.res_kecamatan = k.kode
AND a.res_kabkota = k.kode_kabkota
INNER JOIN t_mst_desa l
ON a.res_propinsi = l.kode_prop
AND a.res_keldesa = l.kode
AND a.res_kabkota = l.kode_kabkota
AND a.res_kecamatan = l.kode_kec
WHERE
a.res_tahunsurvei = 2013
AND a.res_propinsi IN ( '3200', '1600', '1800', '3600' )
ORDER BY
1
You should have an index on your t_responden table ON ( res_tahunsurvei, res_propinsi) to match your where qualification criteria. Additionally, all your inner joins to the other tables where you are applying the IN via sub-selects is killing you. You are already limiting on the "kode"s in the where, so if you apply that as your join you should be good.
Additionally, since all the other tables appear to be more "lookup", I've added "STRAIGHT_JOIN" to tell MySQL to query in the order the tables you have listed

Related

FIND_IN_SET is getting wrong results

First, I searched about the same problem but I didn't find an appropriate solution.
My problem is with the following code, it's returning wrong results:
SELECT FbID,FhID,
FbRef,
FbDate,
(D.AccName) AS DName,
FbQuan,
CONCAT(CategoryName,'-',ProductName) AS ProdName,
(C.AccName) AS CusName,
FhPurPrice,FbSalePrice,
(R.AccName) AS ResoName,
Curr1.CurrencyName,
Curr2.CurrencyName,
Plc1.PlaceName AS FhResoPlaceName,
Plc2.PlaceName AS FbCusPlaceName,
'linked' AS xLinkStatus,
1 AS xStatus
FROM tblfatora2 F2
INNER JOIN tblfatora1 F1 ON F1.FhRef = F2.FhRef
INNER JOIN tblproducts P ON P.ProductID = F1.FhProduct
INNER JOIN tblcategories CT ON CT.CategoryID = P.ProductCategory
INNER JOIN tblaccounts R ON R.AccID = F1.FhReso
INNER JOIN tblaccounts C ON C.AccID = F2.FbCus
INNER JOIN tblaccounts D ON D.AccID = F1.FhDriver
INNER JOIN tblcurrencies Curr1 ON C.AccCurrID = Curr1.CurrencyID
INNER JOIN tblcurrencies Curr2 ON R.AccCurrID = Curr2.CurrencyID
LEFT JOIN tblplaces Plc1 ON F1.FhResoPlace = Plc1.PlaceID
LEFT JOIN tblplaces Plc2 ON F2.FbCusPlace = Plc2.PlaceID
WHERE FIND_IN_SET(`FhID`, '18313,18314')
ORDER BY FbDate, FbID
the results that it gives me are: enter image description here
note: I use FIND_IN_SET here because I can't use (IN) where I use that SQL statement in a procedure inside vb.net code:
Public Sub MySql_GetLinked()
xDtAll = New DataTable()
Dim xPar(0) As MySqlParameter
xPar(0) = New MySqlParameter("#FhID", MySqlDbType.String) With {
.Value = LinkedFatora}
xClsMySql.GetData(xSqlLinked, xDtAll, xPar)
End Sub
So I fill the variable (LinkedFatora) by loop and I use the same SQL statement but I replace (WHERE FIND_IN_SET('FhID', '18313,18314')) with (WHERE FIND_IN_SET('FhID', #FhID)).
I looked for the error's reason but couldn't catch it.
I found the problem, it's changing (WHERE FIND_IN_SET(FhID, '18313,18314')) to (WHERE FIND_IN_SET(FbID, '18313,18314')):
SELECT FbID,FhID,
FbRef,
FbDate,
(D.AccName) AS DName,
FbQuan,
CONCAT(CategoryName,'-',ProductName) AS ProdName,
(C.AccName) AS CusName,
FhPurPrice,FbSalePrice,
(R.AccName) AS ResoName,
Curr1.CurrencyName,
Curr2.CurrencyName,
Plc1.PlaceName AS FhResoPlaceName,
Plc2.PlaceName AS FbCusPlaceName,
'linked' AS xLinkStatus,
1 AS xStatus
FROM tblfatora2 F2
INNER JOIN tblfatora1 F1 ON F1.FhRef = F2.FhRef
INNER JOIN tblproducts P ON P.ProductID = F1.FhProduct
INNER JOIN tblcategories CT ON CT.CategoryID = P.ProductCategory
INNER JOIN tblaccounts R ON R.AccID = F1.FhReso
INNER JOIN tblaccounts C ON C.AccID = F2.FbCus
INNER JOIN tblaccounts D ON D.AccID = F1.FhDriver
INNER JOIN tblcurrencies Curr1 ON C.AccCurrID = Curr1.CurrencyID
INNER JOIN tblcurrencies Curr2 ON R.AccCurrID = Curr2.CurrencyID
LEFT JOIN tblplaces Plc1 ON F1.FhResoPlace = Plc1.PlaceID
LEFT JOIN tblplaces Plc2 ON F2.FbCusPlace = Plc2.PlaceID
WHERE FIND_IN_SET(`FbID`, '18313,18314')
ORDER BY FbDate, FbID

How sum the more than one select query in a single column in mysql?

How to sum this query in single column.
SELECT SUM(IFNULL(ih.amount,0.00)) AS amount
FROM human_resources hr
JOIN functions f
ON hr.function_id = f.id
JOIN params_hours_cost phc
ON phc.function_id = f.id
AND phc.function_id = 2
LEFT
JOIN mca_to_hrc ih
ON hr.id = ih.human_resource_id
JOIN management_cost_action ia
ON ia.id = ih.mca_id
WHERE ia.structure_id = 3
AND ia.year = 2018
AND ia.status_id = 0;
SELECT SUM(IFNULL(ih.amount,0.00)) amount
FROM human_resources hr
JOIN functions f
ON hr.function_id = f.id
JOIN params_hours_cost phc
ON phc.function_id = f.id
AND phc.function_id = 2
LEFT
JOIN mca_to_thrc ih
ON hr.id = ih.human_resource_id
AND ih.mca_id = 2
JOIN management_cost_action ia
ON ia.id = ih.mca_id
WHERE ia.structure_id = 3
AND ia.year = 208
AND ia.status_id = 0;
SELECT SUM(IFNULL(ie.distributed_amount,0.00)) distributed_amount
FROM revenue_and_expenses re
LEFT
JOIN mca_to_ee ie
ON re.id = ie.revenue_expenses_id
WHERE re.transaction_type = 2
AND ie.amount > 0
AND re.year = 2018
AND re.structure_id = 3
Wrap all three queries and SUM the alias amount.
Changed distributed_amount to amount
Amended year typo 208 to 2018
SELECT SUM(a.amount) FROM (
SELECT SUM(IFNULL(ih.amount,0.00)) AS amount
FROM human_resources hr INNER JOIN functions f ON(hr.function_id=f.id)
INNER JOIN params_hours_cost phc ON(phc.function_id = f.id AND phc.function_id=2)
LEFT JOIN mca_to_hrc ih ON(hr.id=ih.human_resource_id)
INNER JOIN management_cost_action ia ON(ia.id=ih.mca_id)
WHERE ia.structure_id = '3'
AND ia.year='2018'
AND ia.status_id='0'
UNION ALL
SELECT SUM(IFNULL(ih.amount,0.00)) AS amount
FROM human_resources hr
INNER JOIN functions f ON(hr.function_id=f.id)
INNER JOIN params_hours_cost phc ON(phc.function_id = f.id AND phc.function_id=2)
LEFT JOIN mca_to_thrc ih ON(hr.id=ih.human_resource_id AND ih.mca_id='2')
INNER JOIN management_cost_action ia ON(ia.id=ih.mca_id)
WHERE ia.structure_id = '3'
AND ia.year='2018'
AND ia.status_id=0
UNION ALL
SELECT SUM(IFNULL(ie.distributed_amount,0.00)) AS amount
FROM revenue_and_expenses re
LEFT JOIN mca_to_ee ie ON(re.id=ie.revenue_expenses_id)
WHERE re.transaction_type=2
AND ie.amount>0
AND re.year='2018'
AND re.structure_id='3') a

mysql where not in to left outer join

I have the following query and would like to convert it to using a left outer join instead of a not in to see if it would run faster that way. It's currently taking this query about 40 seconds to run on our database. I'm not familiar enough with using outer joins for this type of thing to convert it myself.
select
c.contact_id as contact_id,
c.orgid as organization_id,
c.first_name as first_name,
c.last_name as last_name,
a.address_state as state
from cnx_contact as c
inner join cnx_address as a on c.home_address_uid = a.address_uid
where a.address_state = 'OH'
and (c.orgid = 45 or c.orgid = 55)
and c.contact_id NOT IN (
select pc.contact_id
from cnx_contact as c
inner join cnx_address as a on c.home_address_uid = a.address_uid
inner join cnx_contact_group_participant as gp on c.contact_id = gp.contact_id
inner join cnx_contact_participant_role as cr on gp.participant_role_uid = cr.participant_role_uid
inner join cnx_contact_group as cg on gp.group_uid = cg.group_uid
inner join cnx_contact_group_participant as pgp on cg.primary_participant_uid = pgp.participant_uid
inner join cnx_contact as pc on pgp.contact_id = pc.contact_id
where (c.orgid = 45 or c.orgid = 55)
and cr.name = 'Applicant'
);
select
c.columns
from cnx_contact as c
inner join cnx_address as a on c.home_address_uid = a.address_uid
LEFT JOIN
(Subquery goes here) x
ON x.contact _id = c.contact_id
where a.participant_state = 'OH'
and c.orgid IN(45,55)
and x.contact_id IS NULL;

how to join with different tables based on value

i have 4 tables...the parent table is d_checkupinfo and i want to join it with (checkup) or (surgery) or (medicaleq) based on checkupinfo.move_type column value...if it value = 1 then join with checkup table and if value =2 then join with surgery and if value =3 then join with medicaleq.
so how to do this
SELECT
d_checkupinfo.*,
d_branch.*,
d_checkup.* ,
d_surgery.* ,
d_medicaleq.* ,
d_patient.*
FROM d_checkupinfo
LEFT JOIN d_branch WHERE d_checkupinfo.chi_branch_id = d_branch.branch_id
LEFT JOIN d_patient WHERE d_checkupinfo.chi_pi_num = d_patient.pi_id
LEFT JOIN d_checkup WHERE d_checkupinfo.chi_type_id = d_checkup.checkup_id AND move_type = 1
LEFT JOIN d_surgery WHERE d_checkupinfo.chi_type_id = d_surgery.surgery_id AND move_type = 2
LEFT JOIN d_medicaleq WHERE d_checkupinfo.chi_type_id = d_medicaleq.medicaleq_id AND move_type = 3
SELECT
d_checkupinfo.*,
d_branch.*,
d_checkup.* ,
d_patient.*
FROM d_checkupinfo
LEFT JOIN d_branch ON d_checkupinfo.chi_branch_id = d_branch.branch_id
LEFT JOIN d_patient ON d_checkupinfo.chi_pi_num = d_patient.pi_id
LEFT JOIN d_checkup ON d_checkupinfo.chi_type_id = d_checkup.checkup_id WHERE move_type = 1
UNION ALL
SELECT
d_checkupinfo.*,
d_branch.*,
d_surgery.* ,
d_patient.*
FROM d_checkupinfo
LEFT JOIN d_branch ON d_checkupinfo.chi_branch_id = d_branch.branch_id
LEFT JOIN d_patient ON d_checkupinfo.chi_pi_num = d_patient.pi_id
LEFT JOIN d_surgery on d_checkupinfo.chi_type_id = d_surgery.surgery_id WHERE move_type = 2
UNION ALL
SELECT
d_checkupinfo.*,
d_branch.*,
d_medicaleq.* ,
d_patient.*
FROM d_checkupinfo
LEFT JOIN d_branch ON d_checkupinfo.chi_branch_id = d_branch.branch_id
LEFT JOIN d_patient ON d_checkupinfo.chi_pi_num = d_patient.pi_id
LEFT JOIN d_medicaleq on d_checkupinfo.chi_type_id = d_medicaleq.medicaleq_id WHERE move_type = 3

How do I get number of results (rows) in MySQL?

Normally the query below gives me only one result (row).
SELECT
`s`.`FIRMA_UNVANI` AS `FIRMA_UNVANI`,
`s`.`RECNO` AS `RECNO`,
`s`.`BOLGE` AS `BOLGE`,
`s`.`BOLGE_NO` AS `BOLGE_NO`,
`s`.`DURUM` AS `DURUM`,
l.ILCE,
IL.SEHIR,
count(i.recno) AS NUMBER_OF_WORKS
FROM
`SERVISLER` `s`
LEFT JOIN KULLANICI k ON (s.BOLGE = k.KULLANICI)
LEFT JOIN kullanici_cihaz kc ON (k.RECNO = kc.KUL_RECNO)
LEFT JOIN servisler_ilceler c ON (s.RECNO = c.SER_RECNO)
INNER JOIN ILCE l ON (l.RECNO = c.ILCE_RECNO)
INNER JOIN IL ON (IL.ID = l.ILID)
LEFT JOIN ISEMRI i ON (
i.bolge = s.bolge_no
AND i.`SERVIS_DURUMU` = 1
)
WHERE
1 = 1
GROUP BY
s.BOLGE
ORDER BY
IS_SAYISI
LIMIT 0,
15
I get only one result
+----------------+-------+------+---------+------+-----+----------+-----------------+
|FIRMA_UNVANI |RECNO |BOLGE |BOLGE_NO |DURUM |ILCE | SEHIR | NUMBER_OF_WORKS |
+----------------+-------+------+---------+------+-----+----------+-----------------+
|Pirana |2501 |Tekkt |58 |-1 |NT |Istanbul |1428 |
+----------------+-------+------+---------+------+-----+----------+-----------------+
Here the key is RECNO.
I want to count the results:
SELECT
count(0) AS _count
FROM
`SERVISLER` `s`
LEFT JOIN KULLANICI k ON (s.BOLGE = k.KULLANICI)
LEFT JOIN kullanici_cihaz kc ON (k.RECNO = kc.KUL_RECNO)
LEFT JOIN servisler_ilceler c ON (s.RECNO = c.SER_RECNO)
INNER JOIN ILCE l ON (l.RECNO = c.ILCE_RECNO)
INNER JOIN IL ON (IL.ID = l.ILID)
LEFT JOIN ISEMRI i ON (
i.bolge = s.bolge_no
AND i.`SERVIS_DURUMU` = 1
)
WHERE
1 = 1
GROUP BY
s.BOLGE
And I get this wired result:
1428
It was supposed to be 1. Isn't it?
The result is perfectly fine, since you are just counting a 0 for every row instead of i.recno, therefore both resulting in 1428.
To count the number of results, you could wrap your whole query like this to get a resultcount:
SELECT count(*) AS resultcount FROM (
SELECT
`s`.`FIRMA_UNVANI` AS `FIRMA_UNVANI`,
`s`.`RECNO` AS `RECNO`,
`s`.`BOLGE` AS `BOLGE`,
`s`.`BOLGE_NO` AS `BOLGE_NO`,
`s`.`DURUM` AS `DURUM`,
l.ILCE,
IL.SEHIR,
count(i.recno) AS NUMBER_OF_WORKS
FROM
`SERVISLER` `s`
LEFT JOIN KULLANICI k ON (s.BOLGE = k.KULLANICI)
LEFT JOIN kullanici_cihaz kc ON (k.RECNO = kc.KUL_RECNO)
LEFT JOIN servisler_ilceler c ON (s.RECNO = c.SER_RECNO)
INNER JOIN ILCE l ON (l.RECNO = c.ILCE_RECNO)
INNER JOIN IL ON (IL.ID = l.ILID)
LEFT JOIN ISEMRI i ON (
i.bolge = s.bolge_no
AND i.`SERVIS_DURUMU` = 1
)
GROUP BY
s.BOLGE
ORDER BY
IS_SAYISI
LIMIT 0, 15) AS temp
Also note, that WHERE 1=1 is not necessary.
You have used GROUP BY in your query so you will get each group count in result, For example if there 3 group then you will get 3 count result..
If you need to get count of result rows then please use sub query see below
SELECT count(0) AS _count FROM(
SELECT
*
FROM
`SERVISLER` `s`
LEFT JOIN KULLANICI k ON (s.BOLGE = k.KULLANICI)
LEFT JOIN kullanici_cihaz kc ON (k.RECNO = kc.KUL_RECNO)
LEFT JOIN servisler_ilceler c ON (s.RECNO = c.SER_RECNO)
INNER JOIN ILCE l ON (l.RECNO = c.ILCE_RECNO)
INNER JOIN IL ON (IL.ID = l.ILID)
LEFT JOIN ISEMRI i ON (
i.bolge = s.bolge_no
AND i.`SERVIS_DURUMU` = 1
)
WHERE
1 = 1
GROUP BY
s.BOLGE
) AS Temp;