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

时间:2013-05-10 20:42:16

标签: sqlite delphi anydac firedac

背景:

我正在开发一个SQLite磁贴缓存数据库(类似于MBTiles规范),现在只包含一个表Tiles,其中包含以下列:

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

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

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

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

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

问题:

你会使用哪个AnyDAC(FireDAC)组件来频繁查询SQLite表中的3个整数列值(假设是100k记录),并且可以加载找到的blob流?

你会使用:

  • 查询类型组件(我说执行相同的准备查询可能会有效,不是吗?)
  • 内存表(我害怕它的大小,因为tile表中可能存有几个GB,或者它是以某种方式流式传输的?)
  • 不同的东西?

2 个答案:

答案 0 :(得分:3)

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

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

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

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

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

答案 1 :(得分:0)

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

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

对于上述查询,我​​会考虑从fiBlobs中排除FetchOptions,以便在用户从结果集中读取切片时移动地图视图时保存一些I / O时间请求的区域超出了可见视图(您停止阅读并且从不阅读其余区域)。