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 / 问题 / 228041
Accepted
crokusek
crokusek
Asked: 2019-01-25 17:15:08 +0800 CST2019-01-25 17:15:08 +0800 CST 2019-01-25 17:15:08 +0800 CST

如何交叉应用以在视图上逐行操作?

  • 772

我们有一个针对单项查询优化的视图(200 毫秒无并行性):

select * 
    from OptimizedForSingleObjectIdView e2i
   where ObjectId = 3374700

它还适用于一小组静态 ID(~5)。

select * 
    from OptimizedForSingleObjectIdView e2i
   where ObjectId in (3374700, 3374710, 3374720, 3374730, 3374740);

但是,如果对象来自外部来源,那么它会生成一个缓慢的计划。执行计划显示视图部分的执行分支忽略了 ObjectId 上的谓词,而在原始情况下它使用它们来执行索引查找。

select v.*
  from 
     (
       select top 1 ObjectId from Objects
        where ObjectId % 10 = 0
        order by ObjectId
     ) o  
  join OptimizedForSingleObjectIdView v -- (also tried inner loop join)
    on v.ObjectId = o.ObjectId;

我们不希望投资于“双重”优化非奇异案例的视图。相反,我们“寻求”的解决方案是对每个对象重复调用一次视图,而不求助于 SP。

大多数情况下,以下解决方案逐行调用视图。但是这次不是,甚至不是只有 1 个对象:

select v.*
  from
     (
       select top 1 ObjectId 
         from Objects 
        where ObjectId % 10 = 0 -- non-trivial predicate
        order by ObjectId
     ) o
   cross apply
    (
      select top 2000000000 *
        from OptimizedForSingleObjectIdView v_
       where ObjectId = o.ObjectId 
       order by v_.SomeField
    ) v;

有一次我认为有人声称交叉应用在调用 UDF 时保证逐行执行,但这也失败了:

create function FunctionCallingView(@pObjectId bigint)
returns table
as 
return select *
  from OptimizedForSingleObjectIdView 
 where ObjectId = @pObjectId;             

select v.*
  from
     (
       select top 1 ObjectId 
         from Objects 
        where ObjectId % 10 = 0
        order by ObjectId
     ) o
 cross apply FunctionCallingView(o.ObjectId) v

添加选项(强制顺序)没有帮助——但是视图中已经有两个散列提示。暂时删除它们并没有帮助并且减慢了单个案例的速度。

这是基于函数的慢速案例的估计计划的片段。1行的估计是正确的。最右边(未显示)是存在不包括前 1 个结果的搜索谓词的地方。这似乎与我们遇到的其他情况类似,在其他情况下,来自表搜索的单个探测值未用作其他地方的搜索谓词。

在此处输入图像描述

sql-server execution-plan
  • 1 1 个回答
  • 1382 Views

1 个回答

  • Voted
  1. Best Answer
    Paul White
    2019-01-26T01:59:11+08:002019-01-26T01:59:11+08:00

    如果不使用引入新的 T-SQL 执行范围的东西,例如非内联(多语句)表值函数,就不可能完全保证评估外部查询的每一行的视图。BEGIN...END这几乎是针对您之前的问题How to use merge hints to isolate complex queries in SQL Server的建议。

    有一次我认为有人声称交叉应用在调用 UDF 时保证逐行执行

    这不适用于内联表值函数,因为定义在优化开始之前扩展到调用查询中。


    也就是说,您可以做一些事情来强烈鼓励期望的结果。

    执行计划显示视图部分的执行分支忽略了谓词,ObjectId而在原始情况下它使用它们来执行索引查找。

    您期望ObjectId使用索引查找每个驱动行来“在视图内”评估值。这是相关的嵌套循环连接(应用)执行方式。请注意,使用APPLYT-SQL 语言元素并不能保证物理执行将使用应用样式。

    听起来好像 SQL Server 选择使用在Nested Loops JoinObjectId运算符测试的值来执行。这是一种不相关的或简单的嵌套循环连接执行模式。

    这很可能是由您在视图中使用的连接提示引起的。通常应避免连接提示,因为它们极大地限制了优化器的自由度,而不仅仅是针对连接的物理类型。特别是,连接提示还会强制整个查询的连接顺序(就像您使用了FORCE ORDER提示一样)并阻止与聚合放置和策略相关的多项优化,以及其他许多事情。

    如果你真的必须在视图中加入提示(我强烈建议你通常避免这样做),你可能会发现获得你想要的计划形状的最可靠方法是:

    1. 使用视图定义(不引用视图)创建一个内联( RETURNS TABLE) 函数。
    2. @ObjectId作为函数的参数提供。
    3. 以更可能进行索引查找的方式使用函数体内的参数放置谓词。
    4. 如果确实每次使用都应导致查找,则可以使用函数内部的表FORCESEEK提示。
    5. 使用 调用新的内联函数APPLY。

    我通常不喜欢使用特定的语法和提示来强制执行特定的物理计划形状。通过参数化查询并使用计划指南保证计划形状,您可能会取得更大的成功。

    • 10

相关问题

  • 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