SQL:速度提升 - 在cond1或cond2上左连接

时间:2011-02-16 15:52:10

标签: sql performance join left-join

SELECT DISTINCT  a.*, b.*
FROM             current_tbl a
LEFT JOIN        import_tbl  b 
                 ON ( a.user_id = b.user_id 
                   OR ( a.f_name||' '||a.l_name = b.f_name||' '||b.l_name)
                 )
  • 两张基本相同的表格
  • 我无法访问表结构或数据输入(因此无需清理主键)
  • 有时,user_id会填充在一个而不是其他
  • 有时名字是平等的,有时它们不是

我发现通过匹配user_id或名字/姓氏,我可以获得大部分数据。我在名称之间使用' '以避免一个用户具有与另一个姓氏相同的名字并且两个都缺少另一个字段的情况(不太可能,但似乎合理)。

此查询运行在33000毫秒,而个性化它们每个约200毫秒。

  • 我已经迟到了,现在不能直接思考
  • 我认为我可以执行UNION并且只按名称查询user_id不存在(默认连接是user_id,如果user_id不存在,那么我想通过名)
  • 以下是任何想要帮助的人的免费积分

请不要求执行计划。

8 个答案:

答案 0 :(得分:4)

看起来您可以轻松避免字符串连接:

OR ( a.f_name||' '||a.l_name = b.f_name||' '||b.l_name)

将其更改为:

OR ( a.f_name = b.f_name AND a.l_name = b.l_name)

答案 1 :(得分:4)

不是连接名字和姓氏并比较它们,而是尝试单独比较它们。假设您拥有它们(如果不这样做,则应该创建它们),这样可以提高在名字和姓氏列上使用索引的机会。

SELECT DISTINCT  a.*, b.*
FROM             current_tbl a
LEFT JOIN        import_tbl  b 
                 ON ( a.user_id = b.user_id 
                   OR (a.f_name = b.f_name and a.l_name = b.l_name)
                 )

答案 2 :(得分:2)

如果人们的建议没有提供大幅度的提速,那么您的真正问题可能是两个可能的连接条件的最佳查询计划是不同的。对于这种情况,您可能希望执行两个查询并以某种方式合并结果。这很可能会使您的查询变得更加丑陋。

我在这种情况下使用的一个模糊技巧是从UNION ALL查询中执行GROUP BY。这个想法看起来像这样:

SELECT a_field1, a_field2, ...
  MAX(b_field1) as b_field1, MAX(b_field2) as b_field2, ...
FROM (
      SELECT a.field_1 as a_field1, ..., b.field1 as b_field1, ...
      FROM current_tbl a
        LEFT JOIN import_tbl b
          ON a.user_id = b.user_id
    UNION ALL
      SELECT a.field_1 as a_field1, ..., b.field1 as b_field1, ...
      FROM current_tbl a
        LEFT JOIN import_tbl b
          ON a.f_name = b.f_name AND a.l_name = b.l_name
  )
GROUP BY a_field1, a_field2, ...

现在数据库可以使用最有效的计划来完成两个连接中的每一个。

(警告这种方法有一个缺点。如果current_tbl中的一行加入import_tbl中的多行,那么你将以非常奇怪的方式合并数据。)

附带的随机性能提示。除非您有理由相信存在潜在的重复行,否则请避免使用DISTINCT。它强制使用隐式GROUP BY,这可能很昂贵。

答案 3 :(得分:1)

我真的不明白为什么要连接这些字符串。看起来就像你的经济放缓一样。这有用吗?

SELECT DISTINCT  a.*, b.* 
FROM             current_tbl a 
LEFT JOIN        import_tbl  b  
                 ON ( a.user_id = b.user_id  
                   OR ( a.f_name = b.f_name AND a.l_name = b.l_name) 
                ) 

答案 4 :(得分:0)

这是另一种丑陋的方式。

SELECT a.*
  , CASE WHEN b.user_id IS NULL THEN c.field1 ELSE b.field1 END as b_field1
  , CASE WHEN b.user_id IS NULL THEN c.field2 ELSE b.field2 END as b_field2
  ...
FROM current_tbl a
  LEFT JOIN import_tbl b
    ON a.user_id = b.user_id
  LEFT JOIN import_tbl c
    ON a.f_name = c.f_name AND a.l_name = c.l_name;

这避免了任何GROUP BY,并且以一种合理的方式处理冲突的匹配。

答案 5 :(得分:0)

尝试使用JOIN提示:

http://msdn.microsoft.com/en-us/library/ms173815.aspx

我们遇到了与我们的一个查询相同类型的行为。作为最后的手段,我们添加了LOOP提示,查询运行得更快。

值得注意的是,微软说这是关于JOIN的提示:

  

由于SQL Server查询优化器通常会为查询选择最佳执行计划,因此我们建议提示,包括仅供有经验的开发人员和数据库管理员使用的最后手段。

答案 6 :(得分:0)

我老板上次工作..我发誓..他认为使用UNIONS总是比OR更快。

例如..而不是写

从员工中选择*,其中Employee_id = 12或employee_id = 47

他会写(并让我写)

从员工中选择*,其中employee_id = 12 联盟 从员工中选择* employee_id = 47

SQL Sever优化器说在某些情况下这是正确的做法..我有一个朋友在微软的SQL Server团队工作,我给他发了电子邮件,他告诉我我的统计数据已经过时了或类似的东西。

我从来没有真正得到一个很好的答案为什么工会更快,似乎真的反直觉。

我不建议你这样做,但在某些情况下它可以提供帮助。

答案 7 :(得分:0)

另外还有两件事 - 除非你绝对需要它,否则我们就可以获得不同的条款.. n

更重要的是,您可以轻松摆脱连接中的连接,例如(请原谅我缺乏mySQL知识)

SELECT DISTINCT a。,b。 来自current_tbl a LEFT JOIN import_tbl b                  ON(a.user_id = b.user_id                    OR(a.f_name = b.f_name和a.l_name = b.l_name)                  )

我在类似情况下进行了一些测试,通过摆脱连接中的简单连接显示性能提升10倍