如何使用 MATLAB 和 JDBC 加速表检索?

2024-02-10

我正在使用 MATLAB 调用的 JDBC 访问 PostGreSQL 8.4 数据库。 我感兴趣的表基本上由不同数据类型的各个列组成。他们是通过时间戳来选择的。

由于我想检索大量数据,因此我正在寻找一种使请求比现在更快的方法。


我现在正在做的事情如下: 首先我建立与数据库的连接并调用它DBConn。下一步是准备一个 Select 语句并执行它:

QUERYSTRING = ['SELECT * FROM ' TABLENAME '...
WHERE ts BETWEEN ''' TIMESTART ''' AND ''' TIMEEND ''''];

QUERY = DBConn.prepareStatement(QUERYSTRING);
RESULTSET = QUERY.executeQuery();

然后我将列类型存储在变量 COLTYPE 中(1 表示FLOAT, -1 为BOOLEAN其余为 0 - 几乎所有列都包含FLOAT)。下一步是对每一行、每一列进行处理,并通过相应的方法检索数据。FNAMES包含表的字段名。

m=0; % Variable containing rownumber

while RESULTSET.next()
  m = m+1;

  for n = 1:length(FNAMES)

    if COLTYPE(n)==1 % Columntype is a FLOAT
      DATA{1}.(FNAMES{n})(m,1) = RESULTSET.getDouble(n);
    elseif COLTYPE(n)==-1 % Columntype is a BOOLEAN
      DATA{1}.(FNAMES{n})(m,1) = RESULTSET.getBoolean(n);
    else
      DATA{1}.(FNAMES{n}){m,1} = char(RESULTSET.getString(n));
    end

  end

end

当我完成我的请求后,我关闭语句和连接。

我没有 MATLAB 数据库工具箱,因此我正在寻找没有它的解决方案。


我知道请求每个字段的数据是非常低效的。尽管如此,我还是没能找到一种方法来一次获取更多数据 - 例如同一列的多行。有什么办法可以做到吗?您还有其他加快请求速度的建议吗?


Summary

为了加快速度,请使用 Database Toolbox 或自定义 Java 代码将循环和列数据类型转换下推到 Java 层。 Matlab 到 Java 方法的调用开销可能是让您丧命的原因,并且无法使用普通 JDBC 进行块获取(一次调用中的多行)。确保您使用的 JDBC 驱动程序上的旋钮设置正确。然后优化昂贵的列数据类型(如字符串和日期)的传输。

(注意:我还没有对 Postgres 这样做过,但对其他 DBMS 这样做过,这也适用于 Postgres,因为其中大部分是关于它上面的 JDBC 和 Matlab 层的。)

Details

将循环下推到 Java 以获取块

更快地实现这一点的最直接方法是将行和列上的循环向下推送到 Java 层,并将数据块(例如一次 100 或 1000 行)返回到 Matlab 层。从 Matlab 调用 Java 方法会产生大量的每次调用开销,并且会在 M 代码中循环 JDBC 调用(请参阅MATLAB OOP 速度慢还是我做错了什么? https://stackoverflow.com/questions/1693429/is-matlab-oop-slow-or-am-i-doing-something-wrong/1745686#1745686- 完全披露:这就是我的答案)。如果您像这样从 M 代码调用 JDBC,那么您将在每一行的每一列上产生开销,而这可能是您现在执行时间的大部分。

JDBC API 本身不支持像 ODBC 那样的“块游标”,因此您需要将该循环深入到 Java 层。像 Oleg 建议的那样使用数据库工具箱是一种方法,因为他们用 Java 实现了较低级别的游标内容。 (可能正是出于这个原因。)但是,如果您不能拥有数据库工具箱依赖项,您可以编写自己的瘦 Java 层来执行此操作,并从 M 代码中调用它。 (可能通过与您的自定义 Java 代码耦合并知道如何与其交互的 Matlab 类。)使 Java 代码和 Matlab 代码共享块大小,在 Java 端缓冲整个块,使用原始数组而不是尽可能使用列缓冲区的对象数组,并让您的 M 代码批量获取结果集,将这些块缓冲在原始列数组,然后将它们连接在一起。

Matlab层的伪代码:

colBufs = repmat( {{}}, [1 nCols] );
while (cursor.hasMore())
    cursor.fetchBlock();
    for iCol = 1:nCols
        colBufs{iCol}{end+1} = cursor.getBlock(iCol); % should come back as primitive
    end
end
for iCol = 1:nCols
    colResults{iCol} = cat(2, colBufs{iCol}{:});
end

旋转 JDBC DBMS 驱动程序旋钮

确保您的代码向 M 代码层公开 DBMS 特定的 JDBC 连接参数,并使用它们。阅读您的特定 DBMS 的文档并适当地修改它们。例如,Oracle 的 JDBC 驱动程序默认将默认获取缓冲区大小(其 JDBC 驱动程序中的缓冲区大小,而不是您正在构建的缓冲区大小)设置为大约 10 行,这对于典型的数据分析集大小来说太小了。 (每次缓冲区填满时,都会导致到数据库的网络往返。)简单地将其设置为 1,000 或 10,000 行就像打开出厂时设置为“关闭”的“Go Fast”开关。使用示例数据集对您的速度进行基准测试,并绘制结果图表以选择适当的设置。

优化列数据类型传输

除了为您提供块获取功能之外,编写自定义 Java 代码还提供了针对特定列类型进行优化类型转换的可能性。处理完每行和每单元的 Java 调用开销后,您的瓶颈可能会出现在日期解析以及将字符串从 Java 传回 Matlab 中。通过将 SQL 日期类型转换为 Matlab,将日期解析推入 Javadatenums(如Java双倍,带有列类型指示器),因为它们正在被缓冲,可能使用缓存来避免重新计算同一组中的重复日期。 (注意TimeZone问题。考虑乔达时间。)转换任何BigDecimals to double在Java方面。 cellstr 是一个很大的瓶颈 - 单个 char 列可能会淹没多个 float 列的成本。如果可以的话,将窄 CHAR 列作为二维字符而不是 cellstr 返回(通过返回一个大的 Javachar[]然后使用reshape()),转换为cellstr如有必要,在 Matlab 端。 (返回一个JavaString[]转换为cellstr效率较低。)并且您可以通过将低基数字符列作为“符号”传回来优化它们的检索 - 在 Java 端,构建唯一字符串值的列表并将它们映射到数字代码,然后返回字符串作为数字代码的原始数组以及数字 -> 字符串的映射;在 Matlab 端将不同的字符串转换为 cellstr,然后使用索引将其扩展为完整数组。这会更快并且节省大量内存,因为写时复制优化将重复使用相同的原始字符数据来表示重复的字符串值。或者将它们转换为categorical or ordinal如果合适的话,用对象代替 cellstr。这个符号优化可以是big如果您使用大量字符数据并拥有大型结果集,则会获胜,因为您的字符串列以大约原始数字速度传输,这要快得多,并且它减少了 cellstr 的典型内存碎片。 (数据库工具箱现在也可能支持其中一些东西。我已经有几年没有实际使用它了。)

之后,根据您的 DBMS,您可以通过将 DBMS 支持的所有数字列类型变体包含到 Matlab 中适当的数字类型的映射,并尝试在模式中使用它们或在 SQL 中进行转换来提高速度询问。例如,甲骨文的BINARY_DOUBLE可能比平常快一点NUMERIC像这样完整地浏览 db/Matlab 堆栈。 YMMV。

您可以考虑通过用更便宜的数字标识符替换字符串和日期列来优化此用例的架构,可能作为分隔查找表的外键以将它们解析为原始字符串和日期。具有足够模式知识的查找可以在客户端缓存。

如果您想疯狂,您可以在 Java 级别使用多线程,让它异步预取并在单独的 Java 工作线程上解析下一个结果块,如果您有大量数据,则可能会并行化每列日期和字符串处理。当您对前一个块进行 M 代码级处理时,光标块的大小。不过,这确实增加了难度,而且理想情况下会带来较小的性能提升,因为您已经将昂贵的数据处理推到了 Java 层。把这个留到最后。并检查 JDBC 驱动程序 doco;它可能已经有效地为您做到了这一点。

各种各样的

如果您不愿意编写自定义 Java 代码,您仍然可以通过更改 Java 方法调用的语法来获得一些加速obj.method(...) to method(obj, ...). E.g. getDouble(RESULTSET, n)。这只是 Matlab OOP 的一个奇怪的怪癖。但这不会带来太大的好处,因为您仍然需要为每次调用的 Java/Matlab 数据转换付费。

另外,请考虑更改您的代码,以便您可以使用?SQL 查询中的占位符和绑定参数,而不是将字符串作为 SQL 文本进行插值。如果您正在执行自定义 Java 层,那么定义您自己的 @connection 和 @preparedstatement M 代码类是一个不错的方法。所以它看起来像这样。

QUERYSTRING = ['SELECT * FROM ' TABLENAME ' WHERE ts BETWEEN ? AND ?'];
query = conn.prepare(QUERYSTRING);
rslt = query.exec(startTime, endTime);

这将为您提供更好的类型安全性和更可读的代码,并且还可以减少查询解析的服务器端开销。在只有几个客户端的情况下,这不会给您带来太大的加速,但它会让编码变得更容易。

定期分析和测试您的代码(在 M 代码和 Java 级别),以确保您的瓶颈位于您认为的位置,并查看是否有参数需要根据您的数据集大小进行调整,无论是在行数、列数和类型。我还喜欢在 Matlab 和 Java 层构建一些仪器和日志记录,以便您可以轻松获得性能测量(例如,让它总结解析不同列类型所花费的时间、Java 层中的时间以及Matlab 层,以及等待服务器响应的时间(由于管道可能不会太多,但你永远不知道))。如果您的 DBMS 公开了其内部工具,也许也可以将其拉入,这样您就可以看到服务器端时间都花在哪里了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 MATLAB 和 JDBC 加速表检索? 的相关文章

随机推荐

  • 空向量的大小

    运行以下程序g 4 8 2在 32 位 Linux 系统上给出输出 12 vector
  • 将 CSV 文件(包含空字符串和重复项)导入 DynamoDB

    我有一个 CSV 文件 我正在尝试将其导入到 Amazon DynamoDB 因此 我将其上传到 S3 设置 EMR 集群 并创建一个外部表 如下所示 hive gt CREATE EXTERNAL TABLE s3 table myite
  • 单元测试是否应该针对 REST API 进行测试?

    一段时间以来 我已经将我的业务逻辑与 REST Api 层分开进行了单元测试 在集成测试中 我根据其 api 测试了服务本身 当然 集成测试并不包括单元测试所包括的所有边缘情况 感觉就像一个过度杀伤和重复的测试代码 但事实上 我还剩下一整层
  • r 将字符串填充到相同的长度

    经过几个小时的搜索应该很简单的内容后 我需要帮助 我想做的事 确保所有字符串都填充为相同的 26 个字符长度 Dataset library stringr names lt structure list names c A ABC ABC
  • JSON 值可以包含多行字符串吗

    我正在编写一个可由 Java 程序读取的 JSON 文件 片段如下 testCases case 1 scenario this the case 1 result this is a very long line which is not
  • 如何动态添加和扩展私有数据集合?

    设想 I have 3个组织 O1 O3 O1 是申请人的组织 O2 O3 管理与他们共享的公共和私人数据 O1 O3 彼此共享私有数据 O1 O2 共享私有数据 网络正在运行 集合已经分发 一切正常 当我现在想要添加更多组织 以千计 O4
  • 为什么从另一个文件导入类会调用 __init__ 函数?

    该项目的结构是 project 主 py 会话 py 蜘蛛 py session py中有一个类 import requests class Session def init self self session requests Sessi
  • 如何通过反射找出方法的可见性?

    Context 我正在尝试学习 练习 TDD 并决定我需要创建一个不可变的类 为了测试 不变性不变量 你能这么说吗 我想我只需通过反射调用类中的所有公共方法 然后检查类之后是否没有更改 这样我以后就不太可能不小心破坏这个不变量了 这本身可能
  • 为什么Python中的元组可以使用reversed但没有__reversed__?

    在讨论中这个答案 https stackoverflow com questions 9449674 how to implement a persistent python list 9449852 9449852我们意识到元组没有 re
  • 更正应用程序的类路径,使其包含类 Log4J2LoggingSystem 和 PropertiesUtil 的兼容版本

    我正在将一个项目从 Spring Boot 2 6 1 迁移到 Spring Boot 3 0 2 但我遇到了 log4j 依赖项版本的问题 我已经修改了所有给我带来问题的依赖项 但我仍然无法解决问题 错误如下 Java HotSpot T
  • Flowplayer 播放一切

    我有一个flowplayer我正在使用它 下面有几张图片 当您点击这些图片时dialog是用这些图片的放大版本创建的 问题是flowplayer永远会在最上面dialog 我尝试过设置z index of the dialog高和flowp
  • 如何在 SwiftUI 中处理拖动到停靠栏图标上的操作?

    我已经设置了一个 SwiftUI 应用程序 它似乎接受拖放到停靠图标上的图像 但我无法弄清楚在应用程序代码中处理拖放图像的位置 如何处理将图像 或任何特定文件 拖放到 SwiftUI 应用程序的停靠图标上 背景 对于使用 NSApplica
  • 将枚举数据绑定到 WPF + MVVM 中的组合框

    我读了这个非常相关的问题在这里 https stackoverflow com questions 58743 databinding an enum property to a combobox in wpf 由于答案中的链接 这非常有帮
  • Golang:将文件附加到现有的 tar 存档中

    如何将文件附加到 Go 中现有的 tar 存档中 我没有看到任何明显的东西docs http golang org pkg archive tar 关于如何去做 我有一个已经创建的 tar 文件 我想在它关闭后向其中添加更多内容 EDIT
  • 为什么我不必在第二个 TableViewController 中释放 ManagedObjectContext

    我有两个显示 CoreData 对象的表视图控制器 一种是详细视图 带句子 一种是概述 带故事 选择一个故事 gt 查看句子 看来我过度释放了管理对象上下文 我最初在 dealloc 的两个 TableViewController 中发布了
  • 优化Python代码

    关于优化此 python 代码的任何提示寻找下一个回文 输入号码可以为1000000位 添加评论 usr bin python def inc lst lng this function first extract the left hal
  • 修复 Swift 3 中的警告“C-style for Statement is deprecated”

    我有更新Xcode到 7 3 现在我对用于创建随机字符串的函数发出警告 我尝试过改变for声明与for i in 0 lt len 然而 警告变成了错误 我怎样才能删除警告 static func randomStringWithLengt
  • Swift stdlib 工具错误

    我在使用 Xcode 8 1 和 Swift 3 编译时遇到此错误 Swift stdlib 工具错误 编译日志的末尾如下所示 Users Library Developer Xcode DerivedData Build Products
  • 让用户将记录器注入 Nodejs 模块的最佳实践

    我为 nodejs 编写了这个模块 可用于通过 sockjs 从任何地方向客户端分派事件 现在我想包括一些可配置的日志记录机制 目前 我将 winston 添加为依赖项 要求它作为每个类中的记录器并使用 logger error logge
  • 如何使用 MATLAB 和 JDBC 加速表检索?

    我正在使用 MATLAB 调用的 JDBC 访问 PostGreSQL 8 4 数据库 我感兴趣的表基本上由不同数据类型的各个列组成 他们是通过时间戳来选择的 由于我想检索大量数据 因此我正在寻找一种使请求比现在更快的方法 我现在正在做的事