As MySQL has very bad performance for NOT IN
query. So I'm trying to rewrite this query by using LEFT JOIN
but it seems that my query results are inconsistent. Not too sure where did i go wrong with this.
Here is my MySQL query:
SELECT DISTINCT '' AS ID,
ADNO,
PDATE,
REMARKS
FROM AOE_tbl
WHERE ADNO NOT IN
(SELECT adno.meta_value AS 'ADNO'
FROM wp_postmeta AS adno
WHERE adno.meta_key = 'adno')
AND ADNO NOT IN
(SELECT ADNO
FROM AOE_tbl
WHERE REMARKS IN ('private', 'trash')
OR STATUS = 'VOIDED')
GROUP BY ADNO;
which I rewrite to:
SELECT DISTINCT '' AS ID,
AOE1.ADNO,
AOE1.PDATE,
AOE1.REMARKS
FROM AOE_tbl AOE1
LEFT JOIN wp_postmeta AS adno ON AOE1.ADNO = adno.meta_value
AND adno.meta_key = 'adno'
LEFT JOIN AOE_tbl AS AOE2 ON AOE1.ADNO = AOE2.ADNO
AND AOE2.REMARKS IN ('private', 'trash')
OR AOE2.STATUS = 'VOIDED'
WHERE adno.meta_key IS NULL
AND AOE2.REMARKS IS NULL
AND AOE2.STATUS IS NULL
GROUP BY AOE1.ADNO;
I need help to see if there's anything I missed out in above query.
Thanks in advance.
AND
has a higher order of precedence than OR
.
The problem is in the join condition for AEO2
. Notice that the addition of the parens will cause the OR
operation to be evaluated before the AND
operator.
... AOE2
on AOE2.ADNO = AOE1.ADNO
AND ( AOE2.REMARKS IN ('private', 'trash')
OR AOE2.STATUS = 'VOIDED'
)
Without the added parens, the AND
operator is evaluated first, then then the OR
condition... which means that query is checking for any rows in the table with status 'VOIDED'
, and not just rows with a matching ADNO
.
The above is equivalent to:
... AOE2
ON ( AOE2.ADNO = AOE1.ADNO
AND AOE2.REMARKS IN ('private', 'trash')
)
OR ( AOE2.ADNO = AOE1.ADNO
AND AOE2.STATUS = 'VOIDED'
)
With this form, the parens are redundant. If we remove them, it would be the same. (The AND
operations evaluated before the OR
operation.
Also, the anti-join condition in the WHERE clause could be simplified. We're guaranteed that AEO2.ADNO will not be NULL if any matching rows are found, which means AEO2.ADNO will be NULL only if no matching rows are found.
Personally, I would avoid the OR
condition. With appropriate indexes available, it's likely that a third anti-join would perform better.
... AOE2
ON AOE2.ADNO = AOE1.ADNO
AND AOE2.REMARKS IN ('private', 'trash')
LEFT
JOIN AOE_tbl AEO3
ON AOE3.ADNO = AOE1.ADNO
AND AOE3.STATUS = 'VOIDED'
WHERE adno.meta_key IS NULL
AND AOE2.ADNO IS NULL
AND AOE3.ADNO IS NULL
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.