使用 AnyDAC (FireDAC) 从 SQLite 表中读取切片数据 (MBTiles) 的最有效方法是啥?

Posted

技术标签:

【中文标题】使用 AnyDAC (FireDAC) 从 SQLite 表中读取切片数据 (MBTiles) 的最有效方法是啥?【英文标题】:What is the most efficient way to read tile data (MBTiles) from SQLite table by using AnyDAC (FireDAC)?使用 AnyDAC (FireDAC) 从 SQLite 表中读取切片数据 (MBTiles) 的最有效方法是什么? 【发布时间】:2013-05-10 20:42:15 【问题描述】:

背景:

我正在开发一个 SQLite 切片缓存数据库(类似于 MBTiles 规范),现在仅由一个表 Tiles 和以下列组成:

X [INTEGER] - 水平切片索引(不是地图坐标)Y [INTEGER] - 垂直切片索引(不是地图坐标)Z [INTEGER] - 切片的缩放级别Data [BLOB] - 流带有平铺图像数据(当前为 PNG 图像)

平铺计算的所有坐标都在应用程序中完成,因此 SQLite R*Tree Module 和相应的 TADSQLiteRTree 类对我来说没有意义。我只需要尽快加载由给定X, Y, Z 值找到的记录的Data 字段blob 流。

除了这个数据库,应用程序还有一个内存缓存,由像这样TTileCache类型的哈希表实现:

type
  TTileIdent = record
    X: Integer;
    Y: Integer;
    Z: Integer;
  end;    
  TTileData = TMemoryStream;    
  TTileCache = TDictionary<TTileIdent, TTileData>;

在计算 X, Y, Z 值的同时请求某个图块时的工作流程将很简单。我会在内存缓存中请求一个磁贴(在应用程序启动时从上表中部分填充),如果在那里找不到磁贴,请询问数据库(即使找不到磁贴,下载它来自磁贴服务器)。

问题:

您将使用哪个 AnyDAC (FireDAC) 组件来频繁查询 SQLite 表中的 3 个整数列值(假设有 10 万条记录),并可选择加载找到的 blob 流?

你会用吗:

查询类型组件(我想说执行相同的准备好的查询可能很有效,不是吗?) 内存表(我担心它的大小,因为磁贴表中可能存储了几 GB,或者它是否以某种方式流式传输?) 有什么不同?

【问题讨论】:

【参考方案1】:

一定要使用TADQuery。除非您将查询设置为Unidirectional,否则它将在内存中缓冲从数据库返回的所有记录(默认为 50)。由于您正在处理 blob,因此应编写查询以检索所需的最少记录数。

使用参数化查询,如下查询

SELECT * FROM ATable
WHERE X = :X AND Y = :Y AND Z = :Z

最初打开查询后,您可以更改参数,然后使用Refresh 方法检索下一条记录。

内存表不能用于从数据库中检索数据,它必须通过查询来填充。它可以用来替换你的 TTileCache 记录,但我不推荐它,因为它比你的内存缓存实现有更多的开销。

【讨论】:

我希望有人能这样回答。感谢您解释内存表(我没有太多时间研究它们的原理)。你是对的;现在,当我了解它们是如何工作的时,这实际上只是对我自己的内存缓存的开销。我将按照准备好的查询的方式使用TADQuery,只需按照您的建议通过随后的Refresh 调用更改参数。感谢您的回答!【参考方案2】:

我会使用TFDQuery 进行如下查询。假设您要在地图上显示获取的图块,您可以考虑一次获取丢失(非缓存)图块区域的所有图块,而不是始终为您的图块网格一一获取图块:

SELECT
   X,
   Y,
   Data
FROM
   Tiles
WHERE
   (X BETWEEN :HorzMin AND :HorzMax) AND 
   (Y BETWEEN :VertMin AND :VertMax) AND 
   (Z = :Zoom)

对于上述查询,我​​会考虑将 fiBlobsFetchOptions 中排除,以节省一些 I/O 时间,以便在您从结果集中读取图块时用户移动地图视图并且请求的区域已用完的可见视图(您停止阅读并且从不阅读其余部分)。

【讨论】:

以上是关于使用 AnyDAC (FireDAC) 从 SQLite 表中读取切片数据 (MBTiles) 的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

AnyDAC (FireDAC) - 在 TBlobField.GetAsString 之后打开事务

AnyDac aka FireDac 无法生成更新查询

使用带有anydac(现在为firedac)脚本的参数获取错误

在 AutoInc 字段中将 AnyDAC 应用程序迁移到 FireDAC 失败

删除记录时出现 NO_SQL_DATA 错误,firedac,delphi 10.3.1

FIREDAC记录SQL日志