sql-server - 由于此查询中定义的提示,查询处理器无法生成查询计划。重新提交查询并且不使用 SET FORCEPLAN

标签 sql-server sql-server-2008 indexing spatial-index sqlgeography

我正在运行以下内容:

DECLARE @g geography;
declare @point nvarchar(50)  =''
declare @i int =0,
        @lat decimal(8,6) =0.0,
        @long decimal(8,6) =0.0,
        @start datetime = getdate()
set @lat =(select (0.9 -Rand()*1.8)*100)
set @long =(select (0.9 -Rand()*1.8)*100)
set @point = (select 'POINT('+CONVERT(varchar(10), @lat)+ '  ' 
             +CONVERT(varchar(10), @long)+')')
SET @g = geography::STGeomFromText(@point, 4326);
SELECT TOP 1000
    @lat,
    @long,
        @g.STDistance(st.[coord]) AS [DistanceFromPoint (in meters)] 
    ,   st.[coord]
    ,   st.id
FROM    Temp st with(index([SpatialIndex_1]))

此查询性能不佳,因为它不使用空间索引,因此我添加了 with(index([SpatialIndex_1])) 来强制执行它。

地理索引如下:

CREATE SPATIAL INDEX [SpatialIndex_1] ON [dbo].Temp
(
    [coord]
)USING  GEOGRAPHY_GRID 
WITH (GRIDS =(LEVEL_1 = LOW,LEVEL_2 = MEDIUM,LEVEL_3 = LOW,LEVEL_4 = LOW), 
CELLS_PER_OBJECT = 16, PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF,
ONLINE = OFF, ALLOW_ROW_LOCKS = OFF, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 95) 
ON [PRIMARY]

现在它给我错误消息

Msg 8622, Level 16, State 1, Line 15 Query processor could not produce a query plan because of the hints defined in this query. Resubmit the query without specifying any hints and without using SET FORCEPLAN.

我可以阅读并理解它告诉我删除提示,问题是为什么它在编译时成功但在运行时失败?我的索引有问题吗?

我需要更改什么才能让 SQL 开始使用空间索引?

要生成一些数据,您可以使用以下脚本。

CREATE TABLE dbo.Temp
    (
    Id int NOT NULL IDENTITY (1, 1),
    Coord geography NOT NULL
    )  ON [PRIMARY]
     TEXTIMAGE_ON [PRIMARY]
GO
ALTER TABLE dbo.Temp ADD CONSTRAINT
    PK_Temp PRIMARY KEY CLUSTERED 
    (
    Id
    ) 
WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
      ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) 
ON [PRIMARY]
GO


declare @i int =0
declare @lat decimal(8,6) =0.0
declare @long decimal(8,6) =0.0
while (@i < 47000)
begin
   set @lat =(select (0.9 -Rand()*1.8)*100)
   set @long =(select (0.9 -Rand()*1.8)*100)
   insert into Temp
   select geography::Point(@lat, @long,4326)
   set @i =@i+1
end
go

CREATE SPATIAL INDEX [SpatialIndex_1] ON [dbo].Temp
(
    [coord]
)USING  GEOGRAPHY_GRID 
WITH (GRIDS =(LEVEL_1 = LOW,LEVEL_2 = MEDIUM,LEVEL_3 = LOW,LEVEL_4 = LOW), 
   CELLS_PER_OBJECT = 16, PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
   SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF,
   ALLOW_ROW_LOCKS = OFF, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 95) 
ON [PRIMARY]
GO

最佳答案

来自here :

最近邻查询必须满足以下要求才能使用空间索引:

  1. 空间索引必须存在于其中一个空间列上,并且 STDistance() 方法必须在 WHERE 和 ORDER 中使用该列 BY 子句。
  2. TOP 子句不能包含 PERCENT 语句。
  3. WHERE 子句必须包含 STDistance() 方法。
  4. 如果 WHERE 子句中有多个谓词,则 包含 STDistance() 方法的谓词必须通过 AND 连接 与其他谓词的连接。 STDistance() 方法不能 位于 WHERE 子句的可选部分中。
  5. ORDER BY 子句中的第一个表达式必须使用 STDistance() 方法。
  6. ORDER BY 中第一个 STDistance() 表达式的排序顺序 子句必须是 ASC。
  7. 必须过滤掉 STDistance 返回 NULL 的所有行。

所以,这应该有效:

DECLARE @g geography;
declare @point nvarchar(50)  =''
declare @i int =0,
        @lat decimal(8,6) =0.0,
        @long decimal(8,6) =0.0,
        @start datetime = getdate()
set @lat =(select (0.9 -Rand()*1.8)*100)
set @long =(select (0.9 -Rand()*1.8)*100)
set @point = (select 'POINT('+CONVERT(varchar(10), @lat)+ '  ' 
             +CONVERT(varchar(10), @long)+')')
SET @g = geography::STGeomFromText(@point, 4326);

SELECT TOP 1000
    @lat,
    @long,
        @g.STDistance(st.[coord]) AS [DistanceFromPoint (in meters)] 
    ,   st.[coord]
    ,   st.id
FROM    Temp st with(index([SpatialIndex_1]))
WHERE @g.STDistance(st.[coord])  IS NOT NULL
ORDER BY @g.STDistance(st.[coord]) asc

即使删除了 WITH INDEX 提示,您也可以检查它是否正在使用空间索引。

关于sql-server - 由于此查询中定义的提示,查询处理器无法生成查询计划。重新提交查询并且不使用 SET FORCEPLAN,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34764637/

相关文章:

sql - 如何衡量数据库索引的成本?

mysql - MySQL 可以在带 ORDER BY 的 RANGE QUERY 中使用索引吗?

sql - SSIS - 跳过丢失的文件

sql - 使用 SSIS 导入/导出向导在数字列中保留 NULL?

sql - 如何将名称和架构相同但目录不同的文本文件导入数据库?

c# - SQL-Server-2008:XML 问题

c++ - 为什么我的字节数组在我将它插入我的数据库时在 0x00 处拆分(SQL SERVER,C++)

java - 从其父 JMenu 获取 JMenuItem 的位置

c# - 在 C# 中验证小数以在 SQL Server 中存储

c# - hibernate查询使用nolock时出现识别错误