【问题标题】:Understanding performance impacts for mysql tuple search了解 mysql 元组搜索的性能影响
【发布时间】:2017-10-27 04:59:29
【问题描述】:

我正在处理这样的表结构 (emp_data)

id   dept_id    emp_id   emp_name      role
1      101       1001      Tom      Good Worker
2      101       1002      Dick     Smart Worker
3      102       1001      Harry    Hard Worker
4      103       1001      Kate      Nice Worker
5      101       1003      Lucy     Great Worker
  • id 是无争议的主键 :)
  • (dept_id, emp_id) 是多列索引

现在,我需要对 (dept_id, emp_id) 上的组合进行一些非常大的搜索。

我使用这样的元组搜索。

select * from emp_data 
where (dept_id, emp_id) in 
  ((101, 1001), 
   (101, 1002), 
   (103, 1001));

当表格很长时,这需要相当长的时间。

但如果我这样做,

select * from emp_data 
where dept_id in (101, 103) 
and (dept_id, emp_id) in 
((101, 1001), 
 (101, 1002), 
 (103, 1001));

它的速度要快得多,甚至快 100 倍。

这里我不明白的是,

  • 为什么即使在索引列上搜索,查询 1 也不快?

---编辑---

我对我的表上的两个查询做了解释。

  • 我真的很困惑 mysql 对第一个查询进行全表扫描。这至少可以得出一个结论 - 在 'in' 子句中使用元组搜索时,索引是无用的。
  • 第二个查询的行数小于且大约等于结果。这意味着在“in”子句中有一个索引列是可行的。

那么,在 in 子句中使用索引列是不是很糟糕?

【问题讨论】:

    标签: mysql database search optimization indexing


    【解决方案1】:

    根据this question,未优化 MySQL 中对元组的支持。正如@O.Jones 在他的评论中所写,MySQL 中的查询计划器是一个非常复杂的野兽,应该工作的东西并不总是像你预期的那样运行。

    我相信您的第二个查询更快,因为第一个 where 子句 dept_id in (101, 103) 减少了使用元组的第二个搜索空间。查询优化器应该自动执行此操作,但至少在您的示例中不这样做。

    我不认为IN 子句是问题所在——它是元组比较扫描整个表而不使用可用索引。

    【讨论】:

      【解决方案2】:

      您的第一个查询基本上是OR 操作。它需要查看您正在检索的每个不同元组的表。所以它会重复搜索几次,而且它还可能使 MySQL 查询规划器无法进行全表扫描。在这种情况下,它对每个元组执行一个。这会产生非常糟糕的性能。

      在您的第二个查询中,第一个子句看起来缩小了您的搜索范围,然后使用了索引。

      在解决此类问题时,您需要使用EXPLAIN 功能。

      如果您要带着这样的需求进入生产环境,可能值得您花时间进行以下一对查询。

      CREATE TEMPORARY TABLE IF NOT EXISTS searchterms AS
      
        SELECT 101 dept_id, 1001 emp_id
        UNION ALL
        SELECT 101 dept_id, 1002 emp_id
        UNION ALL
        SELECT 103 dept_id, 1001 emp_id;
      
      SELECT * 
        FROM emp_data
        JOIN searchterms ON emp_data.dept_id = searchterms.dept_id
                        AND emp_data.emp_id = searchterms.emp_id;
      

      第一个查询将您的元组放入一个临时表中,第二个查询在JOIN 操作中使用该表。它可能会得到更好的优化。但是你应该尝试一下。编写程序创建临时表有点麻烦,但这种方法比IN () 子句扩展得更好。

      【讨论】:

      • 没有临时表是不是矫枉过正。你能看看我的编辑吗? IN子句有那么糟糕吗?
      • 如果我认为临时表有点矫枉过正,我就不会费心推荐临时表。查询优化是一项棘手的工作,因为您试图对 MySQL 服务器中一个庞大、复杂且不断变化的软件(称为查询计划器)进行事后预测。我们这些使用 MySQL 的人试图想出方法来完成我们的工作。你问了,我解释了我解决你问题的方法。这个策略对我搜索两个或 200 个元组很有用。
      【解决方案3】:

      出于性能目的,最好不要使用 IN。

      SELECT * 
      FROM emp_data 
      WHERE (dept_id = 101 AND emp_id = 1001) 
          OR (dept_id = 101 AND emp_id = 1002) 
          OR (dept_id = 103 AND emp_id = 1001)
      

      您可以在每个请求之前使用 EXPLAIN 来检查它们的行为(实际上,在大多数情况下 - 索引不再用于 IN 语句)。

      【讨论】:

      • 嗯.. 在索引列上使用的 IN 太糟糕了。我相信 IN 和 OR 语句的 EXPLAIN 会提供类似的结果?
      • 试试看……即使是主键,它也会有所不同。当然,在某些情况下,它可能是几毫秒,但对于一些项目,它是几秒钟的偏差。此外,您已组合索引(dept_id,emp_id)的有价值的一点;但即使在这种情况下,它也可能与索引(emp_id,dept_id)不同。这取决于哪个 ID 的变化较少。
      • 这个例子是我刚编出来的。我对使用“IN”没有任何保留。但是我只是没有看到任何证明或文档表明它的性能比链接 OR 语句更差。我将尝试进行更多测试。还是谢谢!!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-25
      • 1970-01-01
      • 2019-07-31
      • 2010-11-04
      • 1970-01-01
      相关资源
      最近更新 更多