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 / 问题 / 234096
Accepted
dsuy
dsuy
Asked: 2019-04-07 09:04:07 +0800 CST2019-04-07 09:04:07 +0800 CST 2019-04-07 09:04:07 +0800 CST

谓词的直接值产生不太好的计划

  • 772

我正在使用 StackOverflow 转储来运行一些测试。

特别是,我正在查询这张表:

帖子表

我创建了这个索引:

创建索引

我正在运行以下查询(只是强制索引来测试替代方案)

直接值查询

我得到以下执行计划的成本很高(66.63)。

不太好的计划

这些是运行此查询后的 IO 统计信息:

在此处输入图像描述

然后,我通过提供变量而不是直接值来运行相同的查询

使用变量查询

我得到了一个更好的计划(成本是 0.4385)。

更好的计划

统计数据也更好:

更好的统计数据

起初...我认为 SQL Server 没有将直接值识别为 INT,但既没有类型不匹配也没有隐式转换警告。

我还尝试避免并行性,但在谓词中传递直接值时,我仍然会使用 MAXDOP 1 获得高成本计划(和更高的 IO 统计信息)。

在比较两个计划时,有不同的估计:

在此处输入图像描述

作为谓词的一部分传递直接值有什么问题?

sql-server sql-server-2012
  • 1 1 个回答
  • 129 Views

1 个回答

  • Voted
  1. Best Answer
    Josh Darnell
    2019-04-09T05:14:02+08:002019-04-09T05:14:02+08:00

    作为谓词的一部分传递直接值有什么问题?

    变量和参数的区别

    优化器在计算变量的估计值时使用统计密度向量。

    当“直接”或“静态”值直接嵌入到查询中时,将使用统计直方图。这就是为什么你会得到不同的估计,从而得到不同的计划。

    这是我的估计计划:https ://www.brentozar.com/pastetheplan/?id=SJCduTuKN

    在我 2010 年的 SO 数据库副本中,OwnerUserId 列的密度为 0.000003807058。乘以 3,744,192 行 = 14.2544 行。这正是 IX_Posts_OwnerUserId 估计出来的行数。

    索引搜索估计的屏幕截图

    您可以通过运行以下 DBCC 命令获取有关该索引的统计信息的信息:

    DBCC SHOW_STATISTICS('dbo.Posts', 'IX_Posts_OwnerUserId');
    

    这是(缩写)输出:

    Name                    Updated             Rows
    IX_Posts_OwnerUserId    Apr  8 2019  8:33AM 3744192
    
    All density     Average Length  Columns
    3.807058E-06    4               OwnerUserId
    

    由于 PostTypeId 也是 WHERE 子句的一部分,因此也会自动为该列生成统计信息。该密度向量为 0.25 x 3,744,192 行 = 936,048 行。

    DBCC SHOW_STATISTICS('dbo.Posts', '_WA_Sys_00000010_0519C6AF');
    

    和输出:

    Name                        Updated             Rows
    _WA_Sys_00000010_0519C6AF   Apr  8 2019  9:04AM 3744192
    
    All density Average Length  Columns
    0.25        4               PostTypeId
    

    由于这是一个“AND”谓词,因此估计使用两者中的较低值。

    当您使用静态值而不是变量时,它使用统计直方图。这是该 SHOW_STATISTICS 命令的第三个结果集中。对于您正在使用的键,这是直方图条目:

    RANGE_HI_KEY    RANGE_ROWS  EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
    22656           13040       11371   305                 42.7541
    

    这就是“静态值”计划中 11,371 的估计值的来源。

    直方图在很多时候可以是一个更好的估计,因为它可以更好地处理边缘情况——因为像这样的大表中经常会有一些异常值。

    成本核算差异

    在这种特定情况下,直方图会产生一个完全正确的估计。生成的计划的成本(正确地)高于使用密度向量的成本,因为它必须处理更多的行。

    “低成本”计划认为该搜索将产生 14 行,而实际上产生了 11,371 行。

    逻辑读取

    由于嵌套循环预取,并行计划中的逻辑读取略高。在我的机器上似乎并没有太大的区别——查询的经过时间在 10 毫秒之内。

    并行性实际上没有任何帮助,因为所有行最终都在一个线程上(无论如何在我的机器上)。添加OPTION (MAXDOP 1)有助于缩短执行时间,但不会删除额外的逻辑读取。

    此查询的“额外读取”问题的一个潜在解决方案是通过将 PostTypeId 添加为包含列来完全避免键查找:

    CREATE INDEX IX_Posts_OwnerUserId ON dbo.Posts (OwnerUserId) 
    INCLUDE (PostTypeId) 
    WITH (DROP_EXISTING = ON);
    
    • 4

相关问题

  • 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