When I run this query, it took an average of 1.2421 seconds, which I think is slow, I have added indexing to every single possible column in those WHERE clause. So anymore improvement that I can do to speed up this query? The table that contains most data is the eav which have around 111276 rows/records
SELECT SQL_CALC_FOUND_ROWS eav.entid,
ent.entname
FROM eav,
ent,
catatt ca
WHERE eav.entid = ent.entid
AND ent.status = 'active'
AND eav.status = 'active'
AND eav.attid = ca.attid
AND ca.catid = 1
AND eav.catid = 1
AND ( ca.canviewby <= 6
|| ( ent.addedby = 87
AND canviewby <= 6 ) )
AND ( ( eav.attid = 13
AND ( `char` = '693fafba093bfa35118995860e340dce' ) )
OR ( eav.attid = 3
AND `double` = 6 )
OR ( eav.attid = 45
AND ( `int` = 191 ) ) )
GROUP BY eav.entid
HAVING Count(*) >= 3
EXPLAIN output
catatt table index
eav table index
ent table index
I have simplified Your query to understand it better, removed unnecessary case from where clause, made query planning.
So check this query and put to comment results and let's debug it under my answer:
SELECT
SQL_CALC_FOUND_ROWS
eav.entid,
ent.entname
FROM
eav
INNER JOIN ent ON (eav.entid = ent.entid AND ent.status = 'active')
INNER JOIN catatt ON (eav.attid = catatt.attid AND catatt.catid = 1)
WHERE
eav.catid = 1 AND eav.status = 'active'
AND (catatt.canviewby <= 6 OR ent.addedby = 87)
AND
(
(eav.attid = 13 AND eav.`char` = '693fafba093bfa35118995860e340dce')
OR
(eav.attid = 3 AND eav.`double` = 6)
OR
(eav.attid = 45 AND eav.`int` = 191)
)
GROUP BY eav.entid
HAVING COUNT(eav.entid) > 2
+ also I see You've rarely UPDATE-ing tables (data mostly inserted to these tables) - so try to make these table's engine to be MyISAM
+ create compound indexes from combinations of: attid, char ; attid, double ; attid, int
+ take a look at mysql's configuration and tune it for better query caching and memory usage
Related
I have written a query. It works better. But currently, all tables have 100K rows, and one of my queries returns too slow. Can you please suggest to me how I can optimize the query?
select *
from tbl_xray_information X
WHERE locationCode = (SELECT t.id
from tbl_location t
where CODE = '202')
AND ( communicate_with_pt is NULL || communicate_with_pt='')
AND x.patientID NOT IN (SELECT patientID
FROM tbl_gxp_information
WHERE center_id = '202')
order by insertedON desc LIMIT 2000
Please note here 'patientID' is varchar.
This may run faster:
select *
from tbl_xray_information AS X
WHERE locationCode =
( SELECT t.id
from tbl_location t
where CODE = '202'
)
AND ( x.communicate_with_pt is NULL
OR x.communicate_with_pt = '' )
AND NOT EXISTS ( SELECT 1 FROM tbl_gxp_information
WHERE x.patientID = patientID
AND center_id = '202' )
order by insertedON desc
LIMIT 2000
These indexes may help:
tbl_location: INDEX(CODE)
tbl_gxp_information: INDEX(center_id, patientID) -- (either order)
Since OR is poorly optimized, it may be better to pick either NULL or empty-string for communicate_with_pt (to avoid testing for both).
I'm using vbulletin 5 and getting message from the host that MYSQL Query was killed because it was running over 1 minutes .. I looked at the query and feel there is something wrong with it .. though I don't have enough experience to judge
here is the query ..
SELECT DISTINCT node.starter AS nodeid
FROM node as node
JOIN closure AS closure ON node.nodeid = closure.child
LEFT JOIN node AS starter
ON starter.nodeid = IF(node.starter = 0, node.nodeid, node.starter)
WHERE node.contenttypeid <> 19
AND node.contenttypeid IN ('22','26','23','21','20','25')
AND closure.parent = '2'
AND node.nodeid <> closure.parent
AND node.contenttypeid <> '15'
AND node.userid <> '28030'
AND (node.public_preview = 1
OR
(
(
(
(
starter.parentid IN (1,2,3,6,13,14,15,16,17,18,19,20,21,22,23,24,25,26,247197,257065,7,8,9,12,51,59,62,27,32,33,36,44,45,50,35,34,37,38,39,40,61,60,57,43,42,46,47,28,29,30,31,41,48,49,52,53,54,55,56,58,63,65,64,247199,247200,66)
)
AND node.showapproved > 0
AND node.viewperms > 1
AND node.showpublished > 0
)
)
OR starter.parentid = 9 AND node.userid IN (0)
)
)
ORDER BY node.lastcontent DESC,node.nodeid ASC
LIMIT 500
I'm trying to work around the "You can't specify target table for update in FROM clause" MySQL error, which means I've got a nested subquery (temp table). Note, I'm trying to get a SELECT to work before I move on to the actual UPDATE.
What I've got is a ledger table where I'm trying to find the associated row's calculated unit total using active_units (what the row started with) and with each additional adjustment in active units (there is one payment row and multiple adjustment rows in the same table that are associated by commission ID and schedule number). These are grouped by month_num. So if it's active_units = 18 and there are three adjustment rows, one with active_units_chg = -2, then I should end up with 18 + -2 = 16.
When I do this:
SELECT
active_units
, active_units_chg
, active_units_total
, CRM_commission_payments.active_units + (
SELECT SUM(active_units_chg)
FROM CRM_commission_payments AS cp
WHERE cp.CRM_commissions_item_id = CRM_commission_payments.CRM_commissions_item_id
AND cp.schedule_a_no = CRM_commission_payments.schedule_a_no
AND cp.month_num = CRM_commission_payments.month_num
AND cp.item_active = 1
) AS active_units_cal1
FROM CRM_commission_payments
WHERE CRM_commission_payments.payment_type = 'payment'
AND CRM_commission_payments.CRM_quotes_item_id = 2457
active_units_cal1 is correct for the row. However, when I do this with a nested JOIN'd subquery, I get NULL for active_units_calc.calc_chg:
SELECT
active_units
, active_units_chg
, active_units_total
, CRM_commission_payments.active_units + (
SELECT SUM(active_units_chg)
FROM CRM_commission_payments AS cp
WHERE cp.CRM_commissions_item_id = CRM_commission_payments.CRM_commissions_item_id
AND cp.schedule_a_no = CRM_commission_payments.schedule_a_no
AND cp.month_num = CRM_commission_payments.month_num
AND cp.item_active = 1
) AS active_units_cal1
, active_units_calc.calc_chg
FROM CRM_commission_payments
LEFT JOIN (
SELECT
source.calc_chg
, source.CRM_commissions_item_id
, source.schedule_a_no
, source.month_num
FROM CRM_commission_payments AS cp1
INNER JOIN (
SELECT
SUM(active_units_chg) AS calc_chg
, cp.CRM_commissions_item_id
, cp.schedule_a_no
, cp.month_num
FROM CRM_commission_payments AS cp
WHERE cp.item_active = 1
) AS source
WHERE source.CRM_commissions_item_id = cp1.CRM_commissions_item_id
AND source.schedule_a_no = cp1.schedule_a_no
AND source.month_num = cp1.month_num
) AS active_units_calc ON (
active_units_calc.CRM_commissions_item_id = CRM_commission_payments.CRM_commissions_item_id
AND active_units_calc.schedule_a_no = CRM_commission_payments.schedule_a_no
AND active_units_calc.month_num = CRM_commission_payments.month_num
)
WHERE CRM_commission_payments.payment_type = 'payment'
AND CRM_commission_payments.CRM_quotes_item_id = 2457
What am I doing wrong?
I am trying to optimize this query. Now it takes 28 seconds.
AS used to be missing in my query. After adding, query time dropped 20%
SELECT
g.id,
g.adresid,
g.senaryoid,
g.olayid,
g.gonderilecegitarih
FROM
(
SELECT
adresid
FROM
expose2.800_emsenaryolar_emgidenbulten
WHERE
olayid = '3320'
) AS s
RIGHT JOIN expose2.800_emsenaryolar_emgidenbulten AS g ON s.adresid = g.adresid
WHERE
s.adresid IS NULL
AND g.olayid = '2784'
AND g.durum = '1'
AND g.gonderilecegitarih < DATE_SUB(
'2015-05-13 15:40:15',
INTERVAL 1 DAY
)
If you use s.adresid IS NULL condition in subquery it will join faster then more rows ...
SELECT
g.id,
g.adresid,
g.senaryoid,
g.olayid,
g.gonderilecegitarih
FROM (
SELECT adresid FROM expose2.800_emsenaryolar_emgidenbulten WHERE olayid = '3320' and s.adresid IS NULL
) AS s
RIGHT JOIN expose2.800_emsenaryolar_emgidenbulten AS g ON s.adresid = g.adresid
AND g.olayid = '2784'
AND g.durum = '1'
AND g.gonderilecegitarih < DATE_SUB(
'2015-05-13 15:40:15',
INTERVAL 1 DAY
)
still this query optimized using self join.
For added speed, add this composite index to g:
INDEX(olayid, durum, gonderilecegitarih)
Please provide SHOW CREATE TABLE 800_emsenaryolar_emgidenbulten; I want to verify that you also have an index on adresid.
My problem is that we make a select, and then, for each row, we run 4 differents request SQL (is madness), as you can guess we make a lot of requests, and the system using this is very slow.
SELECT
deal_source.id,
deal_source.source_name,
deal_source.spider_status,
spider.last_success_date
FROM deal_source
JOIN spider
ON deal_source.id = spider.deal_source_id
Then for each row of this query we make:
$total_query = "SELECT count(id) as total
FROM spider_log
WHERE deal_source_id = '$deal_source_id'
AND date_format(date_created, '%Y-%m-%d') = '$lastdate' ";
$added_query = "SELECT count(id) as added
FROM spider_log
WHERE deal_source_id = '$deal_source_id'
AND action = 'added'
AND date_format(date_created, '%Y-%m-%d') = '$lastdate' ";
$extended_query = "SELECT count(id) as extended
FROM spider_log
WHERE deal_source_id = '$deal_source_id'
AND action = 'extended'
AND date_format(date_created, '%Y-%m-%d') = '$lastdate' ";
$duplicate_query = "SELECT count(id) as duplicate
FROM spider_log
WHERE deal_source_id = '$deal_source_id'
AND action = 'duplicate'
AND date_format(date_created, '%Y-%m-%d') = '$lastdate' ";
SELECT d.id,
d.source_name,
d.spider_status,
s.last_success_date,
COUNT(l.id) AS total,
SUM(l.id IS NOT NULL AND l.action='added' ) AS added,
SUM(l.id IS NOT NULL AND l.action='extended' ) AS extended,
SUM(l.id IS NOT NULL AND l.action='duplicate') AS duplicate
FROM deal_source d
JOIN spider s
ON s.deal_source_id = d.id
JOIN spider_log l
ON l.deal_source_id = d.id
ON l.date_created >= s.last_success_date
AND l.date_created < s.last_success_date + INTERVAL 1 DAY
GROUP BY d.id
Some points:
You can optimize performance of each query, using EXPLAIN and the careful adding of indexes.
You can combine all the queries to a big one, so you don't have to hit the database with a lot of queries.
Besides the lots of queries, The date_format(date_created, '%Y-%m-%d') = '$lastdate' is a performance killer because it apples a function (DATE_FORMAT()) to a column (date_created) so no index can be used and the function is called thosuand or million of times (as many rows are examined). Change such conditions - wherever they are in your code - to:
( date_created >= DATE('$lastdate')
AND date_created < DATE('$lastdate') + INTERVAL 1 DAY
)
or even better, if that $lastdate is a date, to:
( date_created >= '$lastdate'
AND date_created < '$lastdate' + INTERVAL 1 DAY
)
and even more better, if date_created is a DATE column, to:
date_created = '$lastdate'