我正在执行以下查询
SELECT COUNT(*)
FROM table
WHERE field1='value' AND (field2 >= 1000 OR field3 >= 2000)
在field1上有一个索引,而另一个索引在field2& field3上合成。
我看到MySQL总是选择field1索引,然后使用其他两个字段进行连接,这非常糟糕,因为它需要加入146.000行。
关于如何改善这一点的建议?感谢
(建议尝试解决方案后编辑)
基于提出的解决方案,我在使用它时在Mysql上看到了这个。
SELECT COUNT(*) FROM (SELECT * FROM table WHERE columnA = value1
UNION SELECT * FROM table WHERE columnB = value2) AS unionTable;
比执行慢很多:
SELECT COUNT(*)
FROM table
WHERE (columnA = value1 AND columnB = value2)
OR (columnA = value1 AND columnC = value3)
有两个合成索引:
index1 (columnA,columnB)
index2 (columnA,columnC)
有趣的是要求Mysql“解释”它在两种情况下始终使用index1并且不使用index2的查询。
如果我将索引更改为:
index1 (columnB,columnA)
index2 (columnC,columnA)
查询到:
SELECT COUNT(*)
FROM table
WHERE (columnB = value2 AND columnA = value1)
OR (columnC = value3 AND columnA = value1)
然后这是我发现Mysql工作的最快方式。
答案 0 :(得分:24)
分解OR
谓词的典型方法是使用UNION
。
请注意,您的示例不适合您的索引。即使您从谓词中省略了field1
,也会有field2 >= 1000 OR field3 >= 2000
,它不能使用索引。如果您分别在(field1, field2)
和(field1,field3)
或field2
或field3
上添加了索引,则可以获得相当快的查询。
SELECT COUNT(*) FROM
(SELECT * FROM table WHERE field1 = 'value' AND field2 >= 1000
UNION
SELECT * FROM table WHERE field1 = 'value' AND field3 >= 2000) T
请注意,您必须为派生表提供别名,这就是子查询的别名为T
的原因。
一个真实的例子。列名和表名已匿名化!
mysql> SELECT COUNT(*) FROM table;
+----------+
| COUNT(*) |
+----------+
| 3059139 |
+----------+
1 row in set (0.00 sec)
mysql> SELECT COUNT(*) FROM table WHERE columnA = value1;
+----------+
| COUNT(*) |
+----------+
| 1068 |
+----------+
1 row in set (0.00 sec)
mysql> SELECT COUNT(*) FROM table WHERE columnB = value2;
+----------+
| COUNT(*) |
+----------+
| 947 |
+----------+
1 row in set (0.00 sec)
mysql> SELECT COUNT(*) FROM table WHERE columnA = value1 OR columnB = value2;
+----------+
| COUNT(*) |
+----------+
| 1616 |
+----------+
1 row in set (9.92 sec)
mysql> SELECT COUNT(*) FROM (SELECT * FROM table WHERE columnA = value1
UNION SELECT * FROM table WHERE columnB = value2) T;
+----------+
| COUNT(*) |
+----------+
| 1616 |
+----------+
1 row in set (0.17 sec)
mysql> SELECT COUNT(*) FROM (SELECT * FROM table WHERE columnA = value1
UNION ALL SELECT * FROM table WHERE columnB = value2) T;
+----------+
| COUNT(*) |
+----------+
| 2015 |
+----------+
1 row in set (0.12 sec)
答案 1 :(得分:6)
我是新来的,所以我不能评论其他人的帖子,但这与David M.和soulmerge的帖子有关。
不需要临时表。 UNION David M.建议不会重复计算,因为UNION意味着一个独特的(即如果联盟的一半存在一行,则在另一半中忽略它)。如果您使用了UNION ALL,您将获得两条记录。
UNION的默认行为是从结果中删除重复的行。可选的DISTINCT关键字除了默认值之外没有任何影响,因为它还指定了重复行删除。使用可选的ALL关键字,不会发生重复行删除,结果包括所有SELECT语句中的所有匹配行。