2

背景:

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

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

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

除此数据库外,应用程序还将具有由此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,或者它是否以某种方式流式传输?)
  • 有些不同 ?
4

2 回答 2

3

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

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

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

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

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

于 2013-05-11T00:44:44.887 回答
0

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

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

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

于 2017-07-10T15:45:59.233 回答