在多个范围内高效查询 MAX

Jos*_*dan 4 performance sql-server-2008 sql-server query-performance

在适当排序的索引覆盖的单个范围内执行 MIN() 或 MAX() 时,SQL Server 执行 TOP() 并因此在仅获取一行后返回值。当搜索条件包含多个范围时,SQL Server 会从两个范围中获取所有索引值并进行流聚合,这比对每个子值执行 TOP() 慢得多。

例如,假设每个客户有大量订单,如下所示:

CREATE TABLE orders
(
  customer_id int,
  quantity int
)
Run Code Online (Sandbox Code Playgroud)

运行此查询:

SELECT MAX(quantity) 
FROM orders
WHERE customer_id IN (1,2)
Run Code Online (Sandbox Code Playgroud)

将导致查询所需的时间是仅指定一个客户 ID 时的数倍。

执行上述查询的最有效方法是什么?相关地,如果需要单独的结果(即 GROUP BY customer_id),最好的方法是什么?

SQL小提琴:http ://sqlfiddle.com/#!3/ef0c6/1

Jon*_*gel 5

这是一个使用 的解决方案CROSS APPLY,它对TOP每个执行相同的查询customer_id

SELECT MAX(b.MaxQuantity) AS quantity
  FROM
  (
    SELECT 1 AS customer_id UNION ALL
    SELECT 2
  ) a
  CROSS APPLY
  (
    SELECT TOP 1
      quantity AS MaxQuantity
      FROM orders o
      WHERE o.customer_id = a.customer_id
      ORDER BY quantity DESC
  ) b;
Run Code Online (Sandbox Code Playgroud)

这与UNION ALL您在 Fiddle 中编写的基于 -based 的查询的工作相同;不同之处在于customer_id输入是从查询的主体中抽象出来的,因此可以轻松转换为使用表变量或表值参数,这将导致静态查询计划,这一点很重要。这种方法适用于少量customer_id值,并且简单地移除外部MAX值将为每个客户返回最大值。我不相信有一种方法可以customer_id使用这些数据结构针对少量s进一步优化此查询(假设customer_ids 是随机的,而不是范围)。

对于大量的customer_idS,它可能更便宜做索引扫描和流合计比许多寻求。为了加快速度,您必须转向某种非规范化的数据结构。MAX索引视图中不支持,因此在应用程序逻辑或触发器中滚动您自己的机制是唯一的方法。根据此表上的读/写比率,这可能比上述方法快也可能不快:您必须在您的确切场景中对其进行测试。