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 / 问题 / 237217
Accepted
Michael B
Michael B
Asked: 2019-05-03 06:13:46 +0800 CST2019-05-03 06:13:46 +0800 CST 2019-05-03 06:13:46 +0800 CST

为什么这个派生表可以提高性能?

  • 772

我有一个以 json 字符串作为参数的查询。json 是一个纬度、经度对的数组。示例输入可能如下。

declare @json nvarchar(max)= N'[[40.7592024,-73.9771259],[40.7126492,-74.0120867]
,[41.8662374,-87.6908788],[37.784873,-122.4056546]]';

它调用一个 TVF,计算一个地理点周围 1、3、5、10 英里距离的 POI 数量。

create or alter function [dbo].[fn_poi_in_dist](@geo geography)
returns table
with schemabinding as
return 
select count_1  = sum(iif(LatLong.STDistance(@geo) <= 1609.344e * 1,1,0e))
      ,count_3  = sum(iif(LatLong.STDistance(@geo) <= 1609.344e * 3,1,0e))
      ,count_5  = sum(iif(LatLong.STDistance(@geo) <= 1609.344e * 5,1,0e))
      ,count_10 = count(*)
from dbo.point_of_interest
where LatLong.STDistance(@geo) <= 1609.344e * 10

json 查询的目的是批量调用这个函数。如果我这样称呼它,那么性能非常差,只需 4 分就需要将近 10 秒:

select row=[key]
      ,count_1
      ,count_3
      ,count_5
      ,count_10
from openjson(@json)
cross apply dbo.fn_poi_in_dist(
            geography::Point(
                convert(float,json_value(value,'$[0]'))
               ,convert(float,json_value(value,'$[1]'))
               ,4326))

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

但是,将地理结构移动到派生表中会导致性能显着提高,大约 1 秒即可完成查询。

select row=[key]
      ,count_1
      ,count_3
      ,count_5
      ,count_10
from (
select [key]
      ,geo = geography::Point(
                convert(float,json_value(value,'$[0]'))
               ,convert(float,json_value(value,'$[1]'))
               ,4326)
from openjson(@json)
) a
cross apply dbo.fn_poi_in_dist(geo)

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

这些计划看起来几乎相同。既不使用并行性,也都使用空间索引。慢速计划还有一个额外的惰性线轴,我可以通过提示消除它option(no_performance_spool)。但是查询性能没有改变。它仍然慢得多。

使用添加的提示在批处理中运行这两个查询将平等地衡量两个查询。

Sql server 版本 = Microsoft SQL Server 2016 (SP1-CU7-GDR) (KB4057119) - 13.0.4466.4 (X64)

所以我的问题是为什么这很重要?我怎么知道何时应该计算派生表中的值?

sql-server sql-server-2016
  • 1 1 个回答
  • 1972 Views

1 个回答

  • Voted
  1. Best Answer
    Martin Smith
    2019-05-03T08:07:35+08:002019-05-03T08:07:35+08:00

    我可以给你一个部分答案,解释为什么你会看到性能差异——尽管这仍然留下一些悬而未决的问题(例如SQL Server能否在不引入将表达式投影为列的中间表表达式的情况下生成更优化的计划?)


    不同之处在于,在快速计划中,解析 JSON 数组元素和创建 Geography 所需的工作完成了 4 次(函数发出的每一行一次openjson) - 而在慢速计划中完成了超过 100,000次。

    在快速计划中...

    geography::Point(
                    convert(float,json_value(value,'$[0]'))
                   ,convert(float,json_value(value,'$[1]'))
                   ,4326)
    

    分配给函数Expr1000左侧的计算标量openjson。这对应geo于您的派生表定义。

    在此处输入图像描述

    快速计划中的过滤器和流聚合参考Expr1000。在慢速计划中,它们引用了完整的底层表达式。

    流聚合属性

    在此处输入图像描述

    过滤器执行 116,995 次,每次执行都需要表达式求值。流聚合有 110,520 行流入其中以进行聚合,并使用此表达式创建三个单独的聚合。110,520 * 3 + 116,995 = 448,555. 即使每个单独的评估需要 18 微秒,这也会为整个查询增加 8 秒的额外时间。

    您可以在计划 XML 中的实际时间统计中看到这一点的效果(下面用红色注释,从慢计划和蓝色为快速计划 - 时间以毫秒为单位)

    在此处输入图像描述

    流聚合的经过时间比其直接子节点大 6.209 秒。并且大部分子时间都被过滤器占用了。这对应于额外的表达式评估。


    顺便说一句....一般来说,带有标签的底层表达式只计算一次并且没有重新评估,但在这种情况下,从这里发生的执行时间差异很明显,这是不确定的。Expr1000

    • 15

相关问题

  • 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