加速(重写?)a不在子选择查询中

时间:2017-09-05 17:35:03

标签: mysql wordpress

从表格中我试图获得

a)满足某些条件的用户,这些条件以表格中的键/值组合保存

OR

b)根本没有该键/值组合的用户

因此,例如,要尝试查找居住在法国或尚未添加其位置的用户,请使用此(简化)查询:

SELECT *
FROM
    current_users
    JOIN current_users um_location ON current_users.id = um_location.id
WHERE
    (
        ( um_location.meta_key = 'location' AND um_location.meta_value = 'France' )
    OR 
        ( current_users.id NOT IN  
            (SELECT current_users.id FROM current_users WHERE current_users.meta_key = 'location' ) 
        )
    )

问题是,当然,运行OR子选择查询(如果它被调用的话)会大大减慢查询速度。而且由于完整查询中有大约5个或6个这样的子选择,因此它的速度太慢了。

还有另一种方法吗?更快的方式?

3 个答案:

答案 0 :(得分:0)

将OR条件更改为UNION查询而不是OR

SELECT * FROM
    current_users
    JOIN current_users um_location ON current_users.id = um_location.id
WHERE
    um_location.meta_key = 'location' AND um_location.meta_value = 'France' 
UNION
SELECT * FROM
    current_users
    JOIN current_users um_location ON current_users.id = um_location.id
WHERE
    current_users.id NOT IN  
    (SELECT current_users.id FROM current_users WHERE 
    current_users.meta_key='location' ) 

答案 1 :(得分:0)

这应该是最简洁的:

SELECT *
FROM current_users
LEFT JOIN current_users AS um_location 
   ON current_users.id = um_location.id
   AND um_location.meta_key = 'location' 
WHERE um_location.meta_value = 'France' 
   OR um_location.meta_value IS NULL
;

...但是作为isaace的回答提示,MySQL并不理想地处理OR条件。 所以,这可能会表现得更好。

SELECT *
FROM current_users
LEFT JOIN current_users AS um_location 
   ON current_users.id = um_location.id
   AND um_location.meta_key = 'location' 
WHERE um_location.meta_value = 'France' 
UNION
SELECT *
FROM current_users
LEFT JOIN current_users AS um_location 
   ON current_users.id = um_location.id
   AND um_location.meta_key = 'location' 
WHERE um_location.meta_value IS NULL
;

..如果你有meta_value索引,它可能只会有所作为;因为问题是MySQL在呈现OR时会倾向于忽略索引。

编辑:由于开始使用架构设计的类型,这些查询可能会出现一些奇怪的问题,使用“位置”条目作为连接左侧的行;试试这个。

SELECT *
FROM current_users AS non_location
LEFT JOIN current_users AS um_location 
   ON current_users.id = um_location.id
   AND um_location.meta_key = 'location' 
WHERE non_location.meta_key != 'location'
   AND (um_location.meta_value = 'France' 
        OR um_location.meta_value IS NULL
       )
;

答案 2 :(得分:0)

首先,谢谢你们的建议。不幸的是,我无法让它们作为连接工作

LEFT JOIN current_users AS um_location 
ON current_users.id = um_location.id
AND um_location.meta_key = 'location'

没有返回那些尚未进入其位置的用户的记录。

但是,经过大量的工作,我设法解决了这个问题。它不优雅,但有效:

  1. 使用符合某些基本条件的用户子集创建临时表。
  2. 做一个简单的INSERT IGNORE INTO ... SELECT DISTINCT ... FROM current_users添加缺少的位置'有虚假信息。
  3. 然后最终查询包括:

    um_location.meta_value = 'France'
    or
    um_location.meta_value = 'dummyinfo'
    

    它的速度并不快,但由于这是一个仅为管理员用户服务的过程,因此他们可以等待......;)

    再次感谢您的帮助!