2

我有这个查询:

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”等于 a OR b OR c 等。

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

我希望在某种程度上有所帮助

4

5 回答 5

2

首先,将列数据类型更改为varchar. 尽管您可能听说过char所谓的速度更快,但代价是节省一点 CPU 来大幅增加 I/O(一个非常糟糕的交易)。

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

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

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

这是进行 JOIN 的一种可能方法:

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
于 2012-08-03T21:35:00.747 回答
1

首先,正如其他人所建议的那样,对于此数据,VARCHAR 比 CHAR 更好。CHAR 不会更快。

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

并行运行相等查找。跑步:

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

于 2012-08-04T01:44:16.190 回答
1

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

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

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

于 2012-08-03T22:02:20.257 回答
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')

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

UNION ALL 应该比 UNON 快得多,因为您的选择是互斥的,您不需要像 union 那样删除查询。

于 2012-08-03T22:12:00.563 回答
0

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

于 2012-08-03T23:09:42.517 回答