优化查询,仅在返回行数小于一定数量时才返回

and*_*ss6 1 sql-server sql-server-2017

我有一个查询,它首先计算要返回的行数,如果它低于限制,则返回这些行,否则不返回任何内容。

对于上下文:我有一张地图,仅在某个缩放级别后才显示一些点。但是,我的用户现在希望地图只要屏幕上有空间就显示点,而不是具有预定义的最小缩放级别。这意味着现在每当他们在地图上移动时,我都会有两个查询,而不是一个:一个是知道有多少项目,另一个是实际返回它们。负载可能会翻倍。我想过这样做:

SELECT p.ACOLUMN, p.ANOTHERCOLUMN, p.LATITUDE, p.LONGITUDE 
FROM table p 
where p.LATITUDE < @latMax)
and p.LATITUDE > @latMin) 
and p.LONGITUDE < @lngMax)
and p.LONGITUDE > @lngMin)
and (SELECT count(*) 
FROM table
where LATITUDE < @latMax
and LATITUDE > @latMin
and LONGITUDE < @lngMax
and LONGITUDE > @lngMin)) < 200 -- example limit value
Run Code Online (Sandbox Code Playgroud)

查看实际执行计划,我看到 SQL Server 2017 在同一个索引上搜索了两次:

实际执行计划显示相同的非聚集索引查找发生两次

它当然也在两个搜索中读取相同数量的行。有没有办法删除那些重复的搜索?或者是否有另一种更理想的方式来做我正在尝试的事情?

Aar*_*and 6

我并不是说一直到申请的往返。在这种情况下,我认为存储过程是“应用程序”的一种形式。

DECLARE @c int;

SELECT @c = COUNT(*) FROM dbo.table WHERE ...;

IF @c < 200
BEGIN
    SELECT cols FROM dbo.table WHERE ...;
END
Run Code Online (Sandbox Code Playgroud)

如果应用程序总是期望一个空的或非空的结果集,你可以这样做:

DECLARE @c int;

SELECT @c = COUNT(*) FROM dbo.table WHERE ...;

SELECT TOP (CASE WHEN @c <= 200 THEN @c ELSE 0 END) cols 
  FROM dbo.table WHERE ...;
Run Code Online (Sandbox Code Playgroud)

是的,您必须读取表两次(在少于 200 行的情况下;TOP (0) 应该短路),但我没有看到避免这种情况的方法,除非您可能首先将行转储到临时结构中(如果您的 I/O 比您的网络快得多,但您仍然最多只能写入 201 行,这可能仍然比在网络上移动更多行要好得多):

SELECT TOP (201) cols INTO #f FROM dbo.table WHERE ...;

IF @@ROWCOUNT <= 200
BEGIN
  SELECT cols FROM #f;
END

DROP TABLE #f;
Run Code Online (Sandbox Code Playgroud)

你也可以试试这个,但我不确定结果会比你原来的更好,这完全取决于 SQL Server 是否认为它不必两次实现 CTE:

;WITH c AS 
(
   SELECT cols, rn = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
   FROM dbo.table WHERE ...
)
SELECT cols FROM c WHERE NOT EXISTS (SELECT 1 FROM c WHERE rn > 200);
Run Code Online (Sandbox Code Playgroud)