3

前几天我的查询有问题。一个大型数据集大约需要 10 秒。查询看起来像这样:

SELECT a.* from Document as a
LEFT JOIN Waybill as b on a.waybill = b.id
WHERE a.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d'
OR b.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d'

这运行得很慢。但是,然后我将其更改为:

SELECT a.* from Document as a
LEFT JOIN Waybill as b on a.waybill = b.id
WHERE a.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d'
UNION ALL
SELECT a.* from Document as a
LEFT JOIN Waybill as b on a.waybill = b.id
WHERE b.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d'

这花了大约 0.01 秒,尽管这两个查询基本上产生了相同的结果!我查找了官方的 MySQL 文档,并在这里发现了一个有趣的评论:

在 OR 情况下使用索引会失去速度优势 (4.1.10):

SELECT * FROM a WHERE index1 = 'foo' UNION SELECT * FROM a WHERE index2 = 'baar';

SELECT * FROM a WHERE index1 = 'foo' OR index2 = 'bar';

所以,我的问题有 3 个部分:

  • 在生产系统(即数据集非常大的地方)的选择查询中使用 OR 子句真的很糟糕吗?
  • 这个 OR 查询可以通过索引以某种方式调整吗?现在,我用于过滤的查询中的两列实际上都已编入索引。我可以创建一些棘手的复合索引以使 OR 像 UNION ALL 一样快吗?
  • 这是特定于供应商的问题,还是我在使用 Oracle 或 Postgresql 时会遇到同样的问题?
4

2 回答 2

2

OR本身并不坏。与 SQL 中的几乎任何其他构造一样,它可能是一个好主意,也可能不是一个好主意。

您发现优化器有问题。. . 和许多数据库共有的一种。当您的OR条件来自不同的表时,优化器很难利用索引。

您改进的解决方案有效,因为每个子查询都可以利用索引。

您可能会发现以下版本比第一个版本更好,但比第二个版本差:

SELECT d.*
FROM Document d
WHERE d.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d' OR
      (EXISTS (SELECT 1
               FROM Waybill b
               WHERE d.waybill = b.id AND
                     b.enterpriseGuid = '763a3ac3-a3c7-4379-9735-2a4a96e87e5d'
              )
      );
于 2015-10-02T11:23:08.363 回答
0

这是一个与优化器相关的问题,因此引擎/版本/表统计信息等可能会有所不同。

实际上你不能说全表扫描总是比两次索引扫描然后整理结果(即union运算符)差。这取决于索引的选择性。仍然必须非常小心OR,这是真的。

于 2015-10-02T11:35:59.880 回答