greatCircleDistance 在 ClickHouse 中:避免全表扫描

发布: (2026年4月21日 GMT+8 00:18)
3 分钟阅读
原文: Dev.to

Source: Dev.to

Cover image for greatCircleDistance in ClickHouse: Avoiding Full Table Scans

问题

在处理位置数据时,一个常见的问题是:

如何计算存储在数据库中的两个坐标之间的距离?

如果你使用 ClickHouse,无需在数据库外部处理——它内置了相应的函数。

正确工具:greatCircleDistance

greatCircleDistance(lat1, lon1, lat2, lon2)

它返回地球上两点之间的最短距离,单位为

示例

SELECT greatCircleDistance(13.0827, 80.2707, 12.9716, 77.5946) AS distance_meters;

上述查询返回金奈(Chennai)和班加罗尔(Bangalore)之间的距离。

看似简单… 但有陷阱

一个天真的查询,例如:

SELECT city
FROM locations
WHERE greatCircleDistance(lat, lon, 13.0827, 80.2707) < 5000;

在大表上可能会触发全表扫描。

为什么会这样

ClickHouse 的索引是 稀疏的,旨在进行 范围裁剪。它们在以下条件下表现良好:

WHERE lat BETWEEN x AND y

但在以下条件下则不行:

WHERE greatCircleDistance(lat, lon, x, y) < 5000

因为函数是对列值进行计算,ClickHouse 无法利用索引高效跳过数据。

更佳方案(你实际上应该做的)

先使用边界框过滤缩小数据集,然后再应用精确的距离计算。

边界框过滤

SELECT city
FROM locations
WHERE lat BETWEEN (13.0827 - 0.05) AND (13.0827 + 0.05)
  AND lon BETWEEN (80.2707 - 0.05) AND (80.2707 + 0.05)
  AND greatCircleDistance(lat, lon, 13.0827, 80.2707) < 5000;

边界框是一种近似,它在执行精确的 greatCircleDistance 检查之前先缩小搜索空间。

为什么有效

  • lat BETWEEN … → 使用索引
  • lon BETWEEN … → 进一步减少行数
  • greatCircleDistance → 仅对已过滤的子集应用

因此,查询避免了对整张表的扫描。

实际使用场景

  • 配送半径过滤
  • 查找附近的用户
  • 基于地理位置的分析
  • 共享出行系统

一个重要的注意点

  • 坐标必须是 (而非弧度)。
  • 顺序始终是 (lat, lon)。调换顺序会得到错误结果。

结语

greatCircleDistance 功能强大,但盲目使用会影响性能。在 ClickHouse 中,查询设计往往比调用的函数更重要。了解 何时以及如何 使用 greatCircleDistance——通常在进行友好索引的预过滤之后——可以确保地理查询高效且可扩展。

0 浏览
Back to Blog

相关文章

阅读更多 »

SQL 中的子查询和 CTE

在使用 SQL 时,你最终会遇到单个查询不足以解决问题的情况。你需要将问题拆分为多个部分,计算中间结果……

SQL 初学者:核心概念简明

《SQL for Beginners: Essential Concepts Made Simple》封面图片 https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/h...