了解mysql元组搜索的性能影响

时间:2017-05-26 10:26:17

标签: mysql database search optimization indexing

我正在研究像这样的表结构(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)上的组合进行一些非常大的搜索。

我使用tuple搜索,就像这样。

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子句中使用索引列是不是很糟糕?

3 个答案:

答案 0 :(得分:1)

根据this question,对MySQL中的元组的支持没有得到优化。正如@ O.Jones在他的评论中写道,MySQL中的查询计划程序是一个非常复杂的野兽,而应该工作的东西并不总是像你期望的那样。

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

我不相信IN子句是问题 - 这是一个元组比较,它扫描整个表而不使用可用的索引。

答案 1 :(得分:0)

您的第一个查询基本上是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 ()子句更好地扩展。

答案 2 :(得分:0)

出于性能目的,最好不要使用 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语句)。