如何用其他功能替换/优化IN?

时间:2017-09-01 09:34:55

标签: mysql sql optimization

我正在从表history中选择数据,我需要确保accountid的行等于1customidNULL ,但如果不是 - 那么我必须检查customid IN是否STRING我提供的自定义ID列表为SELECT h.* FROM history h WHERE h.accountid = '1' AND IF(h.customid IS NULL, h.userid = 100, h.customid IN ('1','2','3','4') )

示例:

IN

这是我的问题:我必须查找customid的列表非常大。由于这个原因,我的查询可以运行超过30秒。

如何优化id方法,还有其他方法可以在STRING列表中查找extra_link_args吗?

4 个答案:

答案 0 :(得分:1)

使用和/或组合代替if

SELECT h.* 
FROM history h
WHERE h.accountid = '1' 
AND ((h.customid IS NULL and h.userid = 100)
or h.customid IN ('1','2','3','4'))

答案 1 :(得分:0)

您可以替换" IN"与" EXISTS"。

而" IN"收集结果,然后处理这些结果。 " EXISTS"每当他发现一个条件被证明是真的时,它就会停止处理。

如前所述@JohnHC和@jarlh:

  

你应该用和/或替换IF或CASE。

SELECT h.* 
FROM history h
WHERE h.accountid = '1' 
AND ((h.customid IS NULL and h.userid = 100)
or h.customid EXISTS('1','2','3','4'))

运气,

答案 2 :(得分:0)

首先,请确保customid上有索引,因为您正在对列进行查找。

其次,如果您的值列表很长,请考虑将它们批量插入临时表(可以有自己的索引)并进行连接而不是IN

CREATE TEMPORARY TABLE target_customid (customid VARCHAR(256) PRIMARY KEY);

-- Insertion can be done as a batch statement, check your database driver
-- for specifics.
INSERT INTO target_customid VALUES('1'),('2'),('3'),('4');

-- Use a left join to check if customid is in the target list
SELECT h.*
FROM history h
LEFT JOIN target_customid t USING(customid)
WHERE h.accountid = '1' AND (t.customid IS NOT NULL OR h.userid = 100);

-- Or use UNION ALL
SELECT *
FROM history
WHERE accountid = '1' AND userid = 100
UNION ALL
SELECT h.*
FROM history h JOIN target_customid t USING(customid)
WHERE h.accountid = '1' AND h.userid != 100;

-- Finally, drop the temporary table to prevent conflicts in the same
-- session. The temporary table is automatically dropped at the end of
-- the session, so this step is unnecessary if the session ends here.
DROP TEMPORARY TABLE target_customid;

答案 3 :(得分:0)

使用将OR转换为UNION的旧技巧:

SELECT  h.*
    FROM  history h
    WHERE  h.accountid = '1'
      AND  h.customid IS NULL
      AND  h.userid = 100
 UNION ALL
 SELECT  h.*
    FROM  history h
    WHERE  h.accountid = '1'
      AND  h.customid IN ('1', '2','3','4') ) 

(在第二个选择中,测试1/2 / ...意味着NOT NULL。)

然后,您需要此复合索引,其顺序为:

INDEX(accountid, customid, userid)