【问题标题】:Storing Blobs in Seperate Tables with SQLite?使用 SQLite 将 Blob 存储在单独的表中?
【发布时间】:2015-04-07 14:40:44
【问题描述】:

我正在使用此SQLite Plugin 作为移动应用程序从“无限”存储限制中受益。基本上我有base64 imagedata 并且需要将它存储在数据库中。

此外,我还有一些其他表和一个 Masterdata,其中存储了主键以及一些附加信息,例如 albumName

使用外键设置关系

为了处理数据库的关系方面,我最初使用外键声明并创建了如下表(为简单起见仅显示了两个表):

      // Master Data
      $cordovaSQLite.execute(db, 
      "CREATE TABLE IF NOT EXISTS \
        Masterdata(\
          id TEXT primary key, \
          albumName TEXT, \
          favorite INTEGER\
        )"
      )

      // Images
      $cordovaSQLite.execute(db, 
      "CREATE TABLE IF NOT EXISTS \
        ImagesData(\
          id TEXT, \
          data BLOB, \
          FOREIGN KEY(id) REFERENCES Masterdata(id)\
        )"
      )

然后,当我只想加载特定相册的图像时,我运行查询:

SELECT Masterdata.id, ImagesData.data FROM ImagesData, Masterdata WHERE Masterdata.album = (?) ["Some album name"]

这工作得很好(一切都按原样加载),但是我立即注意到在处理大型数据集时它会变慢。这是有道理的,因为 base64 字符串的存储空间非常广泛。

将 Blob 存储在单独的表中

所以我读了这个post如果您的数据包含 BLOB,建议考虑将每个 BLOB 存储在单独的表中

我编码如下:

// tableName in the form of 'id'_imagesData
// 'id' is stored also in Masterdata

$cordovaSQLite.execute(db, 
      "CREATE TABLE IF NOT EXISTS "
        + tableName + "(id integer, data BLOB)"
); 

然后我使用查询将数据插入此表中:

"INSERT INTO " + tableName + " (id, data) VALUES (?,?)", parameters
// parameters = [0, base64_imageData_Str]

结果

结果是我注意到加载时间显着增加,即使存储了多个图像(因此有多个表)也是如此。在我看来,这是有道理的,因为我们可以使用 Masterdata 过滤掉选定的专辑 id,然后只从一个表中加载图像。

我的问题是:

  • 这是一个坏的、好的还是好的做法?
  • 拥有大量表格是否有缺点(例如,如果我有 1000 张图像,那么使用此设置我将拥有 1000 个表格)
  • 如果这是不好的做法,有什么更好的推荐方法?

【问题讨论】:

    标签: javascript database sqlite cordova hybrid-mobile-app


    【解决方案1】:

    将每个 blob 存储在自己的表中绝对是不是的方法。我认为这篇文章是推荐你的第一种方法,应该没问题,只是你的查询是错误的。

    SELECT Masterdata.id, ImagesData.data
    FROM ImagesData, Masterdata
    WHERE Masterdata.album = 'some name'
    

    这将Masterdata 中的一行与ImagesData 中的每一行 连接起来,即使ImageData 不属于Masterdata。您需要添加一个连接条件:

    ...
    WHERE Masterdata.album = 'some name' AND ImageData.id = Masterdata.id
    

    或者更好的是,使用显式连接语法:

    SELECT Masterdata.id, ImagesData.data
    FROM Masterdata
    INNER JOIN ImagesData ON ImagesData.id = Masterdata.id
    WHERE Masterdata.album = 'some name'
    

    还要确保Masterdata.idImagesData.id 有索引。

    【讨论】:

    • 谢谢。因此,如果我理解得很好,您建议在大表上执行一个查询,而不是多个较小的查询。有什么你知道的证据吗?
    • @JohnAndrews 您和我的查询都只是一个查询;但是,您的会返回 ImagesData 中的每张图片,如果图片很大,当然需要很长时间才能阅读。我的查询只返回与Masterdata 对象关联的ImageData
    • 啊,是的,我明白了。我更多地考虑将图像存储在单独的表格中与您的查询有何不同?
    • Indexes 在对列进行过滤时使检索更快,以换取一点插入性能。将列设为主键会隐式在其上创建索引,但也会使列唯一,这可能不是您想要的。
    • FROM 子句中删除ImagesData 表;它已经通过JOIN 提供。不确定您所说的“明确声明”是什么意思。
    【解决方案2】:

    好吧,如果它的图像只有为什么不直接作为图像存储在目录中,并在数据库中具有该图像的名称和哈希值。这将允许您进一步减少加载时间。 哈希将让您将来检查服务器上是否发生了更新。 Watsapp 和其他信使会这样做。

    将其保存在受应用程序保护的目录中将确保没有人可以访问。

    如果文件太多,那么考虑分成文件夹->子文件夹->文件。

    希望这会有所帮助。

    【讨论】:

    • 谢谢,我尝试使用 ngCordova 文件,但一直收到编码错误5;到目前为止,没有人提供解决方案(似乎经常退出问题)
    • 我是出于好奇而问的。如果图像保存在手机目录中。仅在 html 的图像属性中给出路径(不使用 ngcordova 文件扩展名),例如“文件://img/image_id.jpg”。这不能实现你目前正在尝试的吗?
    • 我认为它确实会影响它。我尝试了带前缀和不带前缀但一直收到错误,这似乎很常见:stackoverflow.com/questions/29006469/…
    猜你喜欢
    • 2011-04-08
    • 2013-02-08
    • 2014-10-31
    • 2020-04-18
    • 1970-01-01
    • 2010-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多