我遇到了一个我无法解决的奇怪问题。服务器在执行一些 postgis 相关查询时崩溃。一些调试后,使用实例 提供由PostGIS的,它出现在ST_GEOMFROMGeoJSON()函数引起服务器崩溃。
崩溃:
SELECT ST_AsText(ST_GeomFromGeoJSON('{"type":"Point","coordinates":[-48.23456,20.12345]}')) As wkt;
Run Code Online (Sandbox Code Playgroud)
运行正常:
SELECT ST_AsText(
ST_Transform(
ST_GeomFromText('POLYGON((743238 2967416,743238 2967450,
743265 2967450,743265.625 2967416,743238 2967416))',2249)
,4326)
) As wgs_geom;
Run Code Online (Sandbox Code Playgroud)
查看日志时,我发现这些条目与崩溃相关:
2014-11-21 11:27:46 CET LOG: server process (PID 2377) was terminated by signal 11: Segmentation fault
2014-11-21 11:27:46 CET DETAIL: Failed process was running: SELECT ST_AsText(ST_GeomFromGeoJSON('{"type":"Point","coordinates":[-48.23456,20.12345]}')) As wkt;
2014-11-21 11:27:46 CET LOG: terminating any other active server processes
2014-11-21 11:27:46 CET WARNING: terminating connection because of crash of another server process
2014-11-21 …Run Code Online (Sandbox Code Playgroud) 我正在将一个点与一组多边形相交。查询已编入索引,多边形不重叠,但查询计划似乎认为我将返回 18k 行而不是 1 行,这会导致查询计划错误。
特别是查询计划的最右边节点似乎认为 STPointFromText 函数将返回 1000 的基数,并且该点集与几何索引的交集返回 54k 行的 30%。(在表格中运行了 100 万个点,但没有找到实际返回超过 1 行的反例)
这个缩写查询的结果并不可怕,但是当我将它的输出连接到其他任何东西时,高基数估计迫使上游表成为 tablescan+hashmap,即使整个查询返回 1 行。这个扩展查询每秒运行几次,所以我想知道如何优化它。
空间索引是 HHHH,对于大约 80x50 米的最高分辨率(在域的大约 4000 公里最长边上),索引中有 56k 个多边形,预计最小尺寸约为 100 米。
请注意 est 行和实际行之间的差异。
估计的查询计划。
我对数据库管理还是个新手,我正在尝试优化搜索查询。
我有一个看起来像这样的查询,在某些情况下需要 5-15 秒来执行,并且还导致 100% 的 CPU 使用率:
DECLARE @point geography;
SET @point = geography::STPointFromText('POINT(3.3109015 6.648294)', 4326);
SELECT TOP (1)
[Result].[PointId] AS [PointId],
[Result].[PointName] AS [PointName],
[Result].[LegendTypeId] AS [LegendTypeId],
[Result].[GeoPoint] AS [GeoPoint]
FROM (
SELECT
[Extent1].[GeoPoint].STDistance(@point) AS distance,
[Extent1].[PointId] AS [PointId],
[Extent1].[PointName] AS [PointName],
[Extent1].[LegendTypeId] AS [LegendTypeId],
[Extent1].[GeoPoint] AS [GeoPoint]
FROM [dbo].[GeographyPoint] AS [Extent1]
WHERE 18 = [Extent1].[LegendTypeId]
) AS [Result]
ORDER By [Result].distance ASC
Run Code Online (Sandbox Code Playgroud)
该表在 PK 上有一个聚集索引,在geography类型列上有一个空间索引。
所以当我执行上述查询时,它正在执行扫描操作。
所以我在LegendTypeId列上创建了一个非聚集索引:
CREATE NONCLUSTERED INDEX [GeographyPoint_LegendType_NonClustered] ON [dbo].[GeographyPoint] …Run Code Online (Sandbox Code Playgroud) performance index sql-server optimization spatial query-performance
我们有一个简单的 SQL Server 表,其中包含如下所示的地理空间数据:
CREATE TABLE [dbo].[Factors](
[Id] [int] IDENTITY(1,1) NOT NULL,
[StateCode] [nvarchar](2) NOT NULL,
[GeoLocation] [geography] NULL,
[Factor] [decimal](18, 6) NOT NULL,
CONSTRAINT [PK_dbo.Factors] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
Run Code Online (Sandbox Code Playgroud)
我们现在有大约 100k+ 行,但预计会增长到数百万。
我们对其运行查询,如下所示:
declare @state nvarchar(2) = 'AL'
declare @point geography = geography::STGeomFromText('POINT(-86.19146040 32.38225770)', 4326)
select top 3
Lat,
Lon,
Factor,
GeoLocation.STDistance(@point) as Distance
from dbo.Factors
where StateCode = @state and GeoLocation.STDistance(@point) is not null
order by Distance
Run Code Online (Sandbox Code Playgroud)
不过,这有点奇怪。该表中的数据是参差不齐的:例如,我们得到了一个州南部的数据,但没有得到整个州的数据。如果我们搜索的点在我们获得数据的点的几百米内(例如,来自该州的南部),则查询返回亚秒级。但是,如果距离最近的数据点 100 公里(例如,如果目标点来自该州的北部),则查询最多需要 3 分钟左右才能返回。在这两种情况下,查询计划都表明它们是从地理空间索引的扫描开始的,所以这不是有时会发生的问题,SQL Server 无法确定它应该使用有问题的索引。
我的假设是它与地理空间索引的布局方式有关。 …
我将 SQL Server 2008 R2 用于实时位置感知服务。该服务主要从用户接收位置数据(纬度/经度)并返回用户周围的位置。
每个用户每秒发送一次数据。对于报告的每个位置,都有一个查询来检查该用户周围的其他用户并返回有关他们的数据。
我使用 Lat/Lon 作为浮点字段并运行标量函数来查找最近的用户。
我想这种方法不是最好的。我知道 SQL Server 中有空间数据结构,但不知道它们是否好。我应该使用它们吗?如果是这样,最好的方法是什么?
我应该采取什么方法来使此操作尽可能快速和可扩展?
也许 NoSQL 更适合空间数据?
PS - 我说的是在任何给定时间都有成千上万的用户。
看看这个查询
SELECT DISTINCT
TB.ID,
TB.Latitude,
TB.Longitude,
111151.29341326*SQRT(pow(-6.185-TB.Latitude,2)+pow(106.773-TB.Longitude,2)*0.98839228980165) AS Distance
FROM
`tablebusiness` AS TB
join tableauxiliary as TA on TA.BusinessID=TB.ID
WHERE
MBRContains(
GeomFromText ('MULTIPOINT(-6.2317830813328 106.72621691867,-6.1382169186672 106.81978308133)'),
TA.Latlong
)
AND
MATCH (FullTextSearch) AGAINST ('kucing*' IN BOOLEAN MODE)
ORDER BY
Distance
LIMIT
0, 20
Run Code Online (Sandbox Code Playgroud)
这基本上是搜索 TA.LatLong 在 'MULTIPOINT(-6.2317830813328 106.72621691867,-6.1382169186672 106.81978308133)' 框中的所有 biz,并且在该框之后必须包含 ku
这将返回 22 行。
现在将其与此查询进行比较
SELECT DISTINCT
TB.ID,
TB.Latitude,
TB.Longitude,
111151.29341326*SQRT(pow(-6.185-TB.Latitude,2)+pow(106.773-TB.Longitude,2)*0.98839228980165) AS Distance
FROM
`tablebusiness` AS TB
join tableauxiliary as TA on TA.BusinessID=TB.ID
WHERE
MBRContains(
GeomFromText ('MULTIPOINT(-6.2317830813328 106.72621691867,-6.1382169186672 106.81978308133)'),
TA.Latlong
) …Run Code Online (Sandbox Code Playgroud) 我有一张表,里面有大约 200 万条记录。我创建了一个空间索引,使用边界框以外的默认值。我一直注意到有些查询非常快,有些则非常慢。决定因素出现在查询中使用的多边形的大小。
在较大的搜索区域,使用WITH(INDEX(SIX_FT5))会大大减慢查询速度(从 0 秒到 15 秒以上)。在较小的搜索区域,情况正好相反。
以下是我正在测试的一些查询:
快速地:
SELECT TOP(1000)
*
FROM [FT5]
WHERE
shape.STIntersects(geometry::STGeomFromText('POLYGON ((-133462.805381701 -668610.241000959, 2934415.68824241 -668610.241000959, 2934415.68824241 2200521.65831815, -133462.805381701 2200521.65831815, -133462.805381701 -668610.241000959))', 2264)) = 1
Run Code Online (Sandbox Code Playgroud)
减缓:
SELECT TOP(1000)
*
FROM [FT5] WITH(INDEX(SIX_FT5)) -- Index hint is the only difference
WHERE
shape.STIntersects(geometry::STGeomFromText('POLYGON ((-133462.805381701 -668610.241000959, 2934415.68824241 -668610.241000959, 2934415.68824241 2200521.65831815, -133462.805381701 2200521.65831815, -133462.805381701 -668610.241000959))', 2264)) = 1
Run Code Online (Sandbox Code Playgroud)
为什么 WITH 子句有时会减慢速度?
我使用 SQL Server 已经很长时间了,但直到最近才遇到处理空间数据的需要。我进入了一个大量使用它的环境,我的第一个真正挑战是让查询更快地运行(并停止超时),以针对具有地理数据类型列(和索引)的表。
我们使用一个查询来标识该表中在多边形和多多边形中找到的所有地理点。这个表中有超过 9900 万条记录,我不知道如何调整这个野兽的性能!我已经确定聚集索引比需要的大一点,并打算添加一个标识列来做两件事:1) 减小聚集索引的大小。2) 消除插入的页面拆分。虽然我希望从这样做中得到一些缓解,但我并不乐观它会对空间查询有很大帮助。
鉴于我几乎完全缺乏空间数据的知识/经验,我无法做得更好。
Example query:
Declare @OrgID int
Declare @Geog geography
Set @OrgID =100011
/* This will return a multi polygon */
SELECT @Geog = geog
FROM Organization
WHERE orgid= @orgid
Select count(*)
FROM ProblemChild WITH (INDEX(IDX_geog))
WHERE Geog.STIntersects(@geog) = 1)
Table Design:
CREATE TABLE [dbo].[ProblemChild](
[Phone] [char](10) NOT NULL,
[Lat] [float] NOT NULL,
[Lon] [float] NOT NULL,
[Geog] [geography] NOT NULL,
[Recordsource] [varchar](2) NOT NULL
CONSTRAINT [PK_Phone] PRIMARY KEY CLUSTERED
([Phone] ASC)WITH …Run Code Online (Sandbox Code Playgroud) 我们刚刚从 SQL Server 2008 升级到 2014。除了我们在空间索引上遇到的问题之外,它进行得相当顺利。在这张桌子上,我们收到错误
无法在具有唯一索引“lu_unit__geolocation”的对象“sys.extended_index_1527780600_384000”中插入重复的键行。- 重复键值:(0x20330a3504, 95469304)。
空间索引不能有唯一约束,有问题。
我认为更安全的方法是重建索引。我做了一些实验,我发现在 160 万行上重建索引大约需要 50 秒。生产表大约有 550 万行,由于无法在线构建空间索引,因此在无法访问基表时至少需要 3 分钟。
有没有人有在最短的停机时间内重建空间索引的经验?我们可以用 30 秒但不能用 3 分钟。
我收到此错误:
'geography::Point' failed because parameter 1 is not allowed to be null.
Run Code Online (Sandbox Code Playgroud)
在这个sql上:
SELECT [ID], geography::Point([lat], [long], 4326) AS [loc]
FROM (
SELECT [ID], CONVERT(float, [lat]) AS [lat], CONVERT(float, [long]) AS [long]
FROM (
SELECT [ID], [lat],
[long], ROW_NUMBER() OVER (PARTITION BY [ID] ORDER BY [EFFDT] desc) AS [sequence]
FROM [GEO]
) AS temp1
WHERE [sequence] = 1
AND [lat] IS NOT NULL
AND [long] IS NOT NULL
) AS temp2
ORDER BY [ID]
Run Code Online (Sandbox Code Playgroud)
但那里没有空值,而且我只在我们的生产计算机(Production 13.0.4422.0)上收到错误,而在我们的开发计算机(Dev 13.0.1728.2)上却没有收到错误。经过几个小时的搜索和重试后,我发现通过重新排序一些东西,这是可行的:
SELECT [ID], [loc] …Run Code Online (Sandbox Code Playgroud) spatial ×10
sql-server ×8
index ×2
mysql ×1
mysql-5.5 ×1
optimization ×1
performance ×1
postgis ×1
postgresql ×1
t-sql ×1