这个transitive_closure查询需要20秒才能完成!为什么?

时间:2011-06-28 15:32:42

标签: sql-server optimization transactions performance

当我在Member_Contact_Edges表中几乎有500行时,此查询工作得非常好并且快速完成。但是现在,我在这个表中有近1.000行,这个查询需要20-30秒才能完成。我无法弄清楚问题出在哪里。我尝试了Clustered和Non-Clustered索引。我尝试了各种索引组合但没有成功。

 ;WITH transitive_closure(member_a, member_b, distance, path_string) AS

  (SELECT member_a, member_b, 1 AS distance, CAST(member_a as varchar(MAX)) + '.' + CAST(member_b as varchar(MAX)) + '.' AS path_string
          FROM Member_Contact_Edges
          WHERE member_a = @source AND contact_durum=1 -- source

   UNION ALL

   SELECT tc.member_a, e.member_b, tc.distance + 1, CAST(tc.path_string as varchar(MAX)) + CAST(e.member_b as varchar(MAX)) + '.' AS path_string
          FROM Member_Contact_Edges AS e
          JOIN transitive_closure AS tc ON e.member_a = tc.member_b
          WHERE tc.path_string NOT LIKE '%' + CAST(e.member_b as varchar(MAX)) + '.%' AND e.contact_durum=1
   )

   SELECT distance, path_string FROM transitive_closure
          WHERE member_b=@target AND distance <= 3 -- destination
          ORDER BY member_a, member_b, distance;

这就是我称之为存储过程的方法:

   Exec Contacts_KacinciDerece @source = 30284, @target=24688

输出:(这是我的预期,这个查询创建了这个)

Expected output but takes so much time to create

感谢。

2 个答案:

答案 0 :(得分:3)

你有path_string NOT LIKE '%' + CAST(e.member_b as varchar(MAX)) + '.%'

  • 无法优化NOT LIKE或前导通配符LIKE,更不用说两者了
  • path_string无论如何都是计算字段

Member_Contact_Edges中的每一个额外行都会将必须扫描的行数(平方)与索引的任何优势相乘。

O(n^2) 至少:我怀疑更高......

答案 1 :(得分:0)

看起来像NOT LIKE语句是性能的关键。我设法通过限制距离在160ms内运行查询。

但是这里出现问题:

如果我不使用NOT LIKE语句,由于递归选择,它会选择同一个人两次或更多次。

例如;

;WITH transitive_closure(member_a, member_b, distance, path_string) AS

(SELECT member_a, member_b, 1 AS distance, CAST(member_a as varchar(MAX)) + '.' + CAST(member_b as varchar(MAX)) + '.' AS path_string
      FROM Member_Contact_Edges
      WHERE member_a = @source AND contact_durum=1 -- source

UNION ALL

SELECT tc.member_a, e.member_b, tc.distance + 1, CAST(tc.path_string as varchar(MAX)) + CAST(e.member_b as varchar(MAX)) + '.' AS path_string
      FROM Member_Contact_Edges AS e
      JOIN transitive_closure AS tc ON e.member_a = tc.member_b
      WHERE tc.member_b <> e.member_b AND tc.distance<4 AND e.contact_durum=1
)

SELECT distance, path_string FROM transitive_closure
      WHERE member_b=@target AND distance < 4 -- destination
      ORDER BY member_a, member_b, distance;