wxd*_*dan 3 sql-server execution-plan spatial sql-server-2014 query-performance
我有一个经常更新影响某些几何图形的事件的表。几何区域是固定的,但可能有一个事件同时影响多个区域,因此两者之间存在多对多的关系。单个区域也可能同时受到多个事件的影响。
例如:
| 事件ID | 区域编号 |
|---|---|
| 1 | 15 |
| 1 | 31 |
| 2 | 46 |
| 3 | 46 |
| 3 | 55 |
| 4 | 15 |
这些区域在我的表中表示为 ID 值。我需要在空间上表示这些值,因此我需要将这些值连接到包含s 和几何图形的event_id and area_id查找表。area_id不幸的是,这些表位于同一 SQL Server 2014 实例上的两个独立数据库中。
问题是这个连接过程非常慢;返回 18k-24k 行需要 90 秒到 3 分钟不等,具体取决于当前有多少事件处于活动状态。几何查找表包含 84k 行。
事件表结构(为了简单起见,删除了一些附加列):
USE Events_DB;
CREATE TABLE [dbo].[Events](
[EVENTS_ID] [bigint] NOT NULL,
[AREA_ID] [bigint] NOT NULL,
[START_DATE_TIME] [smalldatetime] NULL,
[END_DATE_TIME] [smalldatetime] NULL,
CONSTRAINT [PK_Events] PRIMARY KEY CLUSTERED
(
[EVENTS_ID] ASC,
[AREA_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
几何查找表结构:
USE Geom_DB;
CREATE TABLE [dbo].[Area_Geom](
[AREA_ID] [int] NOT NULL,
[Geom] [geometry] NOT NULL,
CONSTRAINT [Area_Geom] PRIMARY KEY CLUSTERED
(
[AREA_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
我的查询如下。我对事件和区域 ID 使用 CTE,因为它们在完整查询的其他地方使用,但我已将瓶颈缩小到该特定部分。
WITH active_ids (EVENTS_ID, AREA_ID) AS (SELECT DISTINCT EVENTS_ID, AREA_ID
FROM EVENTS
WHERE END_DATE_TIME > getUTCdate())
SELECT geom FROM Area_Geom WHERE area_id IN (SELECT area_id FROM active_ids);
Run Code Online (Sandbox Code Playgroud)
执行计划显示Area_Geom表上主键索引的聚集索引扫描;扫描该表中存储的约 84k 行需要花费近 2 分钟的时间。
我向我们公司的一位 DBA 提出了这个问题,他被难住了。我可以采取其他措施来提高性能吗?我知道连接的跨数据库部分是问题的一部分,不幸的是,我对此无能为力。
我确实注意到两个表上的两个Area_ID值有两种不同的类型(bigint 和 int);然而,将 CTE 中的 Area_ID 转换为 int 对性能几乎没有影响。
好消息!您的查询很快就完成了!
\n\n坏消息!需要很长时间才能去做其他事情。
\n\n考虑到与 CPU 相比,这里的运行时间很长,您可以打赌查询要么被阻止,要么接收结果花了很长时间。
\n如果您运行相同的查询并将其转储到 #temp 表中,这样就不会将结果返回到 SSMS,这应该有助于确定瓶颈是在服务器端还是客户端。
\nWITH \n active_ids AS \n(\n SELECT DISTINCT \n e.AREA_ID\n FROM [EVENTS] AS e\n WHERE END_DATE_TIME > GETUTCDATE()\n)\nSELECT\n a.*\nINTO #active_ids\nFROM active_ids AS a;\n\nSELECT \n a.geom \nINTO #Area_Geom\nFROM Area_Geom AS a\nWHERE area_id IN (SELECT ai.area_id FROM #active_ids AS ai);\n\nSELECT\n ag.*\nFROM #Area_Geom AS ag;\nRun Code Online (Sandbox Code Playgroud)\n