使用OR时的SQL性能问题

时间:2012-08-03 21:23:41

标签: mysql sql performance

我有这个问题:

SELECT stringa FROM table WHERE stringb = 'x' OR stringb = 'y' OR stringb = 'z'

这只是一个缩短版本,实际查询在一个查询中有超过1,000个“OR”子句。

执行需要几分钟,这是不行的。

我尝试过这样的一次查询:

SELECT stringa FROM table WHERE stringb = 'x'
SELECT stringa FROM table WHERE stringb = 'y'
SELECT stringa FROM table WHERE stringb = 'z'

但这需要更长的时间。我也试过这样一个大问题:

SELECT stringa FROM table WHERE stringb = 'x'
UNION
SELECT stringa FROM table WHERE stringb = 'y'
UNION
SELECT stringa FROM table WHERE stringb = 'z'

但这又花了更长时间。

如果有人有任何提高性能的建议,我们将不胜感激。我的桌子是MyISAM,如果它很重要的话。

编辑:

这是表格的结构:

列:

key (CHAR PRIMARY), stringa (CHAR), stringb (CHAR)

行如下所示:( key - stringa - stringb)

key - a - b
key - a - c
key - a - d
key - a - e
key - a - f
key - b - b
key - b - c
key - b - d
key - c - c
key - c - d
key - c - f
key - d - f

等。等等。有近百万行。

我需要选择所有'stringa',其中'stringb'等于OR b OR c等。

当然stringa和stringb不仅仅是'a'和'b',它们包含长度在3到80个字符之间的CHAR。

我希望以某种方式有所帮助

5 个答案:

答案 0 :(得分:2)

首先,将列数据类型更改为varchar。尽管您可能已经听说char据说速度更快,但权衡的是为I / O的大量增加(非常糟糕的交易)节省一点CPU。

其次,如果列stringb上没有索引,则需要索引。索引不必是唯一的。

第三,许多DBMS对数千个OR条件没有问题,但通常这样的事情表示为WHERE stringb IN ('a', 'b', 'c', 'd', 'e' ...)

最后,在许多情况下,如果不提供卓越的性能(尽管在某些DBMS或情况下可能),JOIN至少会提供更高的清晰度和重用性。例如,许多人做的一件事是创建一个字符串拆分函数,当以'a,b,c,d,e'格式传递字符串时,返回一个包含单独行中每个项目的行集。然后加入到这个行集很简单,只要客户端可以构造要拆分的字符串,就可以动态地驱动查询。

这是一种可能的联接方式:

CREATE TEMPORARY TABLE Keys (
   Value varchar(30)
);

INSERT Keys VALUES ('x');
INSERT Keys VALUES ('y');
INSERT Keys VALUES ('z');

SELECT T.SomeColumns
FROM
   YourTable T
   INNER JOIN Keys K
      ON T.stringb = K.Value

答案 1 :(得分:1)

您需要在stringb列上创建索引。

您的问题更多的是您正在进行全表扫描,而不是“或”的效率。传统的方法是在“in”语句中路由值列表。但是,在某些数据库中,这对性能没有影响。

另外,您的字段是在char或varchar中声明的吗?如果它们是char,那么这可能是性能问题的根源。这些将用空格填充,大大增加了存储空间并延长了比较。

答案 2 :(得分:1)

首先,正如其他人所建议的,VARCHAR是比CHAR更好的选择。 CHAR不会更快。

考虑通过KEY(stringb)PARTITIONS 8(这是任意的)对表进行分区,并在(stringb,stringa)上添加索引。这将减少IO,覆盖索引将使返回数据更快。

运行等式查找IN PARALLEL。运行:

SELECT stringa FROM table WHERE stringb  in('x',...)
SELECT stringa FROM table WHERE stringb  in('y',...)
SELECT stringa FROM table WHERE stringb  in('z',...)

三个线程将导致显着的性能提升。

您只需将结果重新组合在一起并不困难。如果要查看,Shard-Query可用于自动将查询与IN()列表并行化:

http://code.google.com/p/shard-query

答案 3 :(得分:0)

尝试

SELECT stringa FROM table WHERE stringb = 'x' 
UNION ALL
SELECT stringa FROM table WHERE stringb = 'y' 
UNION ALL
SELECT stringa FROM table WHERE stringb = 'z' 

SELECT stringa FROM table WHERE stringb in ( 'x', 'y', 'z')

或@ ErikE的解决方案,如果你真的有一千个OR条件。

UNION ALL应该比UNON快得多,因为你的选择是互斥的,你不需要让查询删除表达联合的方式。

答案 4 :(得分:0)

虽然我认为@HLGEM的第二个答案是最好的,但您也可以尝试在查询中使用正则表达式来表示列stringb。