代码之家  ›  专栏  ›  技术社区  ›  Andomar

意外的表扫描ID!=身份证

  •  11
  • Andomar  · 技术社区  · 15 年前

    一个应用程序导致我们的SQL Server 2005数据库负载过重。 我们无法控制应用程序 每分钟运行此查询的次数:

    select id,col1,col2,col3 from table where id != id
    

    注意 身份证件!=身份证 ,表示行不等于自身。毫不奇怪,结果总是找不到行。但是,SQL Server每次运行此查询时都会进行聚集索引扫描!

    ID列定义为:

    varchar(15) not null primary key
    

    查询计划显示了大量的“估计行数”。有人知道为什么SQL Server需要表扫描来找出明显的原因吗?

    13 回复  |  直到 15 年前
        1
  •  2
  •   Lasse V. Karlsen    15 年前

    在阅读了这里的答案和您的编辑之后,让我总结一下您的选择:

    1. 更改MS SQL Server以处理此情况(基本上,与Microsoft支持人员交谈)
    2. 更改应用程序以避免这种情况发生,或以不同的方式进行(基本上,与提出应用程序的公司的支持人员交谈)
    3. 更改为除SQL Server(如果应用程序允许)之外处理此情况的其他内容
    4. 更改为其他应用程序

    这些都不是好的解决方案,但不幸的是,它们是您唯一拥有的解决方案。你得选一个,然后跟着它走。

    我将首先尝试解决方案2,这是一个会/应该花费最短时间来执行的解决方案。

    另一方面,如果那家公司不愿意更改应用程序,那么我会选择解决方案4。这是一个主要的性能缺陷,如果公司不愿意或无法解决这个问题,你必须问问自己,下一个角落还潜伏着什么?

        2
  •  6
  •   Jeff Fritz    15 年前

    我会假装这个问题…提取视图,并复制查询。

    将现有表“table”重命名为“table_org”或其他名称,然后创建如下视图:

    CREATE VIEW table
    AS
    SELECT * FROM table_org
    WHERE id='BOGUSKEY'
    

    现在,您应该让1扫描主键上的表,它应该(像原始查询一样)什么也找不到。应用程序不知道更明智的…

        3
  •  4
  •   Tom H    15 年前

    你最大的问题不是扫描桌子。你最大的两个问题是:

    • 对于您的数据库,您有一个绝对无用的查询,每分钟运行100次。顺便说一句,我猜想查询实际上正试图从表中获取列名,正如MarcGravell所建议的那样。

    更重要的是:

    • 您无法控制访问数据库的对象或内容。

    第二个问题,尤其是最有可能导致你无尽的头痛。假设您是组织中数据团队的一员(因为您正试图解决这个问题),那么您真的应该考虑对组织进行必要的更改以完成您的工作。

    祝你好运!

        4
  •  3
  •   Krishna Chaitanya    15 年前

    每个值与n-1的其余值进行比较。这就是它返回“估计行数”的原因。对于上述问题,最好使用not in。

    这里的文章是解决您问题的一个很好的指针。希望对你有帮助。 http://www.sqlservercentral.com/articles/Performance+Tuning/2924/

        5
  •  3
  •   kervin    15 年前

    我见过这种类型的查询。

    开发人员很可能正在基于用户输入、当前设置或其他一些因素构建“where”子句。在许多情况下,可能是默认实例,它们需要一个仅作为占位符的WHERE子句。这就是他们使用“ID”这样的标准的时候!=id'、'1<>1'等。

    “每分钟数百次”也让我相信这是一个错误的默认占位符。

    有时,它们会使用一个与之相反的条件,如果默认情况需要所有行,则始终计算为true。

    这是一个长期的尝试,但我的建议是看看您是否可以修改应用程序设置,看看这个查询是否消失。您最终可能得到一个较小的结果集,但它的运行频率较低,并且被SQL Server更好地处理。

        6
  •  3
  •   J. Polfer    15 年前

    您可能希望让SQL Server支持团队了解此查询(当列定义为主键时ID<gt;ID)及其导致的完整表扫描,并查看他们是否希望在查询引擎中添加优化以确保这不会导致完整表扫描。

    或者和你无法控制的应用程序的支持团队交谈。

    编辑:尝试TechNet论坛 http://social.msdn.microsoft.com/forums/en-US/sqldatabaseengine/threads/ 报告行为。

        7
  •  2
  •   Aaron Alton    15 年前

    ID列上是否有非聚集索引?如果不是,最有效的方法就是CIX扫描。尝试在ID列上添加一个NCIX——它可能仍然执行一次扫描,但至少在一个非常小的索引上是一次扫描。如果您在SQL Server 2008上,则可以创建一个筛选索引(其中ID<gt;ID),SQL Server将使用(空)筛选索引来满足查询。

        8
  •  2
  •   MatBailie    15 年前

    我几乎羞于接受这个答案,但本着“如果没有理智的东西起作用,就去尝试疯狂的东西”的精神…

        Create a constraint on the table where id = id?
    

    WHERE子句只能返回违反约束的行,定义上没有违反约束的行。在您的案例中,这个额外的(尽管是冗余的)信息可以帮助优化者。它也可能达到无平方根,但在你的情况下,我会给它一个机会,以防万一…

        9
  •  1
  •   Marc Gravell    15 年前

    我不知道为什么是我!=i d在这种情况下需要很长时间(尽管“明显”是主观的-这不一定是一个我会想到的优化…这似乎是一个不寻常的查询;然而,笛卡尔连接是痛苦的。但是一般来说,尝试“Where1=0”-或者如果你只是想要这个模式,也许有点冒险 SET FMTONLY ON .

    编辑:刚看到“我们不控制每分钟运行这个查询的应用程序”…六羟甲基三聚氰胺六甲醚。。。这就很棘手了。

        10
  •  1
  •   stili    15 年前

    由于不太熟悉SQL Server,我认为下面的解决方案也可以应用于SQL Server。

    在Oracle中,我认为您可以通过使用物化视图和重写查询来胜过天真的SQL。物化视图将不包含行,而查询重写将识别SQL并将查询重新路由到空视图。物化视图永远不需要更新,因为它总是空的。

        11
  •  1
  •   Dave W. Smith    15 年前

    在我看来,你有一个伪装成技术问题的政治问题。你可以在技术问题上投入大量的时间和精力,但只要你不断重复“我们无法控制应用程序”,你就无法寻求政治选择。

    你不能控制应用程序,但你可以安排一些影响应用程序。让所有的涉众都知道这个应用程序的行为是如何影响到其他使用该数据库的人的(使用图表,因为您希望快速将此消息传递给管理层)。很明显,这是应用程序作者或微软要解决的问题。这可能会给应用程序的作者带来压力,也可能会产生“好的,好的”。让我们为该应用程序购买另一个数据库“管理层的响应”。

    (对于Microsoft是否已在SQL Server 2008中“修复”此问题,您需要有一个可用的答案。)

        12
  •  1
  •   araqnid    15 年前

    我怀疑sqlserver不知道!=(应为“<>”?)是反反射的(即A!=A总是错误的)它只是看到它不是常量(它取决于结果行中的值),因此将其放入结果过滤器中。因此,“其中ID<>ID”可能与“其中1<>1”非常不同。

    现在,他们当然可以让它检测到这一情况;但我想这并没有被列入他们的优先名单,因为这样做介于“奇怪”和“愚蠢”之间。

    是的,做这个的应用程序很糟糕,我想你已经知道了;)

        13
  •  0
  •   KM.    15 年前

    没有办法让这个不扫描,你要求除了1行以外的所有东西,那就是扫描。您最好希望应用程序停止发送这些查询。