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 / 问题 / 240584
Accepted
Michael B
Michael B
Asked: 2019-06-15 06:33:22 +0800 CST2019-06-15 06:33:22 +0800 CST 2019-06-15 06:33:22 +0800 CST

如何强制 SQL Server 通过视图使用我的空间索引?

  • 772

我有一些表,其中包含存储为 lat long 对的属性的事务。(在我的示例架构中,列和数据点更多)。

一个常见的请求是查找在特定点 X 英里范围内发生的交易,并且只检索附近每个物业发生的 5 次最近的交易。

为了完成这项工作,我决定添加一个封装最新逻辑的视图:

create or alter view dbo.v_example
with schemabinding as
select example_id
      ,transaction_dt
      ,latitude
      ,longitude
      ,latlong
      ,most_recent= iif(row_number() over (partition by latitude,longitude order by transaction_dt desc) < 5,1,null)
from dbo.example;

因此查询可能如下所示:

select *
from dbo.v_example
where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
and most_recent = 1

不幸的是,当我通过视图查询时,SQL Server 不想使用空间索引。如果我删除schemabinding并尝试在视图上添加提示,我会发现查询处理器无法创建计划。

如何封装逻辑并仍然让它使用我的空间索引?

这是一个带有示例数据和计划形状的 db<>fiddle。

该表要大得多,扫描它然后进行聚集索引查找然后找到附近的点要慢得多。

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

1 个回答

  • Voted
  1. Best Answer
    Randi Vertongen
    2019-06-15T08:58:04+08:002019-06-15T08:58:04+08:00

    窗口功能和视图

    最近我回答了一个关于视图和窗口功能的不同问题,但并非所有答案都适用于此处。

    两个区别是这个例子geography在窗口函数上使用了数据类型和过滤器。这里的积极部分是你没有绑定到窗口函数,并且可以使用类似的东西CROSS APPLY来获得一个latitude&longitude组合的最接近的结果。

    上一个问题+答案

    简而言之,在应用过滤之前计算窗口函数。

    例如

    where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
    and most_recent = 1
    

    可以在Paul White 2013 年的这篇博文中找到有关窗口功能和视图的更多信息。

    测试

    作为第一个测试,当ROW_NUMBER()从视图中省略时结果很清楚

    create or alter view dbo.v_example2
    with schemabinding as
    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
    from dbo.example;
    
    set statistics xml on;
    select *
    from dbo.v_example2
    where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
    

    产生预期的高性能查询计划。

    DB<>小提琴


    但是你显然仍然想要额外的过滤

    保持视图+窗口功能

    您可以选择在之后添加窗口功能,如下所示:

    create or alter view dbo.v_example2
    with schemabinding as
    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
    from dbo.example;
    

    &

    set statistics xml on;
    ;WITH CTE AS
    (
    select most_recent= iif(row_number() over (partition by latitude,longitude order by transaction_dt desc) < 5,1,null)
    ,*
    from dbo.v_example2
    where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
    )
    SELECT
    * 
    FROM CTE
    WHERE most_recent is not null;
    

    再次导致预期的执行计划。

    DB<>小提琴


    使用内联表值函数 + 窗口函数

    CREATE FUNCTION dbo.F_Example
    (
        @P1 INT
    
    )  
    RETURNS TABLE
    WITH SCHEMABINDING AS
    RETURN
        (
    SELECT example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
          ,most_recent FROM
    (
    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
          ,most_recent= iif(row_number() over (partition by latitude,longitude order by transaction_dt desc) < 5,1,null)
    from dbo.example
    WHERE latlong.STDistance(geography::Point(40,-74,4326)) <= 1609.344e1
    ) AS A
    WHERE most_recent= @P1
    );
    
    EXEC SP_EXECUTESQL
    N'SELECT * FROM  dbo.F_Example(@P1)',N'@P1 INT',@P1 = 1
    

    产生您期望的查询计划。

    DB<>小提琴

    使用 CTE + 窗口函数

    ;WITH CTE AS
    (
    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
          ,most_recent= row_number() over (partition by latitude,longitude order by transaction_dt desc)
    FROM dbo.example
    WHERE latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
    )
    
    SELECT example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
          ,most_recent
    FROM CTE2
    WHERE most_recent < 5;
    

    使用CROSS APPLY和TOP(4) 不使用窗口函数

    SELECT example_id
          ,a.transaction_dt
          ,latitude
          ,longitude
          ,latlong
    from dbo.example e1
    CROSS APPLY(
    SELECT TOP(4) transaction_dt
    FROM dbo.example e2
    WHERE e1.latitude = e2.latitude  and e1.longitude = e2.longitude
    GROUP BY latitude,longitude,transaction_dt
    ORDER BY transaction_dt desc
    ) as a
    WHERE latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
    AND e1.transaction_dt = a.transaction_dt
    ORDER BY transaction_dt desc;
    

    我使用了,因为结果集不是top(4)基于< 5<= 5

    使用该CROSS APPLY方法时,还要添加一个索引,以删除索引假脱机和排序:

    在此处输入图像描述

    CREATE INDEX IX_latitude_longitude_transaction_dt
    ON dbo.example(latitude,longitude,transaction_dt);
    

    在此处输入图像描述

    不用说,您可以将CROSS APPLY解决方案添加到视图中,并以与以前相同的方式查询它,这里有一个示例。以上所有示例都在一个 DB<>Fiddle here中。


    MichaelB结束解决方案评论

    感谢 Randi,我能够使用您的交叉应用的想法将我的逻辑重写为选择子查询。作为额外的奖励,如果我没有在我选择的列中提及该字段,我不会受到性能影响。

    DB<>小提琴

    create or alter view dbo.v_example2
    with schemabinding as
    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
          ,most_recent= (
              select a.transaction_dt
              intersect
              select top 5 b.transaction_dt
              from dbo.example b
              where a.latitude=b.latitude
                    and a.longitude=b.longitude
              order by transaction_dt desc
          )
    from dbo.example a;
    

    &

    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
    from dbo.v_example2
    where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
          and most_recent is not null
    
    • 5

相关问题

  • 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