AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 197921
Accepted
Peter
Peter
Asked: 2018-02-15 07:25:52 +0800 CST2018-02-15 07:25:52 +0800 CST 2018-02-15 07:25:52 +0800 CST

行估计总是太低

  • 772

我有一个涉及全文搜索的查询,如下所示:

SELECT TOP 30 PersonId,
              PersonParentId,
              PersonName,
              PersonPostCode
FROM dbo.People
WHERE PersonDeletionDate IS NULL
      AND PersonCustomerId = 24
      AND CONTAINS(ContactFullText, '"mr" AND "ch*"')
      AND PersonGroupId IN(197, 206, 186, 198)
ORDER BY PersonParentId,
         PersonName;

这会生成两个主要计划,一个在所有情况下都非常快,另一个在大多数情况下非常慢。

我对这个查询进行了试验,因此不包括 FT 搜索,我发现行估计总是比它们应该的低得多。

如果我运行,update statistics...with fullscan我仍然会从执行计划中的 NC 索引查找操作中看到极其不准确的行估计。

当行估计足够低时,选择循环连接,这通常非常慢(30 多秒)。较高的估计似乎会产生一个涉及合并连接而不是循环连接的好计划。

尽管仍然有最新的统计信息,为什么 SQL Server 仍然不估计行数?

计划:https ://www.brentozar.com/pastetheplan/?id=rkXtE0jzX

当我删除该CONTAINS部分,从而省略全文搜索时,查询速度很快,但索引查找的行估计仍然是 1 估计,实际 2195。

在@Kin 的建议下,我使用了 CONTAINSTABLE,它立即运行并生成了以下计划:https ://www.brentozar.com/pastetheplan/?id=S1hKainzQ 有趣的是没有全文搜索运算符。

在这种情况下, Containstable 需要RANK生成相同的结果集,我用AND RANK > 0它WHERE来生成我想要的结果,它生成了这个计划:https ://www.brentozar.com/pastetheplan/?id=B1U7AA2zm

我现在唯一的问题是为什么行估计仍然不准确,但我现在不那么关心了,因为我的 FT 查询看起来更快、更可靠。很高兴! https://www.brentozar.com/pastetheplan/?id=B1U7AA2zm

@EvanCarroll 统计直方图在这里:https ://pastebin.com/p7s0NvX5

一些后续信息——针对所支持的应用程序的一些典型 FT 搜索查询的执行计划之前/之后

一个

  1. 之前:https ://www.brentozar.com/pastetheplan/?id=SJlAAAN7X (5 秒)
  2. 之后:https ://www.brentozar.com/pastetheplan/?id=H1ltkkSmm (<1 秒)

乙

  1. 之前:https ://www.brentozar.com/pastetheplan/?id=Sy-gxJBQm (40 秒)
  2. 之后:https ://www.brentozar.com/pastetheplan/?id=Sy2VxJrm7 (1 秒)

C

  1. 之前:https ://www.brentozar.com/pastetheplan/?id=r1z5e1rQ7 (2 秒)
  2. 之后:https ://www.brentozar.com/pastetheplan/?id=r1oplkSQm (<1 秒)

丁

  1. 之前:https ://www.brentozar.com/pastetheplan/?id=B1kHf1BQQ (2 分 20 秒)
  2. 之后:https ://www.brentozar.com/pastetheplan/?id=r1D5z1SQm (11 秒)
sql-server sql-server-2016
  • 2 2 个回答
  • 1180 Views

2 个回答

  • Voted
  1. Best Answer
    Kin Shah
    2018-07-08T10:34:23+08:002018-07-08T10:34:23+08:00

    (总结我的评论并作为答案)

    查询重写将解决获得低行估计的问题。正如 Joe Chang 在他的博客文章 Query Optimizer Gone Wild - Full-Text中解释的那样

    根据 Microsoft 文档,CONTAINS 是“在 WHERE 子句中使用的预测”,而 CONTAINSTABLE 充当表。

    使用uses a nested loop join with low row estimates与实际计划相比,您获得了更好的计划(合并连接)。CONTAINSTABLEcontains

    您可以将查询重写为:

    SELECT TOP 30 p.PersonId,
                  p.PersonParentId,
                  p.PersonName,
                  p.PersonPostCode
    FROM dbo.People p
    left join containstable (ContactFullText, '"mr" AND "ch*"') cf on cf.[yourKey] = p.PersonId
    WHERE p.PersonDeletionDate IS NULL
          AND p.PersonCustomerId = 24
          --AND CONTAINS(ContactFullText, '"mr" AND "ch*"')
          AND p.PersonGroupId IN(197, 206, 186, 198)
          AND [RANK] > 0
    ORDER BY p.PersonParentId,
             p.PersonName;
    
    • 4
  2. StrayCatDBA
    2018-02-15T12:27:21+08:002018-02-15T12:27:21+08:00

    全文查询根据 contains 子句中的文本进行部分重新编译。(根据经验)我将冒险猜测 SQL Server 期望来自关系谓词的行数较少,并且正在对 FTS 引擎执行 for-each 循环“查找”。搜索可能是性能杀手。

    如果您想要可预测的性能,那么您可以将查询分成两部分。

    SELECT ... INTO #tmpResults FROM CONTAINSTABLE()...
    
    SELECT ... FROM #tempResults INNER JOIN People ....
    

    你不应该必须这样做,但它有效。

    • 0

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve