使用数据工具包加速 CSV 加载?

使用数据工具包加速 CSV 加载?

我正在使用该datatool包读取一些 CSV 文件。我csvsimple以前用过这个包,但最后我通过添加越来越多的要求打破了这个包。现在我想切换到这个datatool包,加载一次“数据库”并重复使用它们。问题是:加载文件需要很长时间。这些文件分别有大约 1000 行,分别有 13、6 和 8 列,仅加载第一个文件就需要五分钟以上的时间。如果我打开包的详细日志记录datatool,我可以看到加载过程随着读取的数据越来越多而变得越来越慢。这是事实吗(这意味着我必须寻找另一种替代方案)或者我可以做些什么来加快加载过程?

答案1

csvsimple被描述为一种轻量级工具,不支持排序或数据存储,而datatool是一个支持排序和存储的重量级包,正是这些额外的功能使得它datatool比 更慢csvsimple

问题基本上归结为这样一个事实:尽管 TeX 是图灵完备的,但它是一种文档格式化语言,而不是计算机编程语言,并且它没有数组式结构来方便地存储多维数据。在大多数语言中,你可以执行类似这样的操作float[][] array = new float[m][n],然后使用类似这样的操作访问条目,array[i][j]并使用类似这样的操作设置条目的值array[i][j] =价值

然而,在 TeX 中,存储数据的方式基本上有两种:要么在宏中,要么在寄存器中。第一个版本datatool使用宏进行存储,但 2.0 版中内部结构发生了变化,这datatool要归功于 Morten Høgholm,他提供了一种更好的方法,将数据存储在令牌寄存器中。这大大改善了数据查找,但由于整个数据库都存储在单个令牌寄存器中,改变数据(而不是简单的查找)需要将寄存器的内容拆分为需要更改的条目,然后将整个内容与新值重新组合并重置寄存器的内容。从 CSV 文件加载数据库时,需要对数据库中的每个单元格执行此操作。(其他事情也会完成,例如确定给定列的数据类型。)

verbose模式还会增加加载时间。默认情况下,此功能处于关闭状态,但对于没有此verbose模式的大型数据库,看起来好像什么都没有发生。

这是一个示例文档,它只是从名为的文件中加载数据entries.csv

\documentclass{article}

\usepackage{datatool}

\DTLloaddb{entries}{entries.csv}

\begin{document}

\end{document}

我创建了entries.csv一个包含 100 个随机生成的单词的单列文件。包括标题行在内,这个文件共有 101 行。然后我使用 Linuxtime命令编译了这个测试文档:

time pdflatex test.tex

由此产生了:

real   0m0.177s
user   0m0.163s
sys    0m0.012s

开启模式后verbose,结果变为:

real    0m0.184s
user    0m0.163s
sys     0m0.018s

然后我重新尝试了 10 列和 100 行(加上标题行),结果是:

verbose离开:

real    0m1.072s
user    0m1.059s
sys     0m0.012s

verbose在:

real    0m1.121s
user    0m1.100s
sys     0m0.014s

然后再次使用 10 列和 10,000 行(加上标题行):

verbose离开:

real    1m44.484s
user    1m44.488s
sys     0m0.017s

verbose在:

real    1m47.569s
user    1m47.460s
sys     0m0.064s

因此关闭verbose模式可以节省几秒钟的时间,但通过让 TeX 仅设置令牌寄存器的内容,可以实现更显著的改进一次而不是反复重置它,这可以使用datatooltk在编译文档之前。这是一个 Java 应用程序,可以快速加载和排序从 CSV、XLS 或 ODS 文件加载的数据或从 MySQL 数据库导入的数据。

现在

time datatooltk --csv entries.csv --output entries.dbtex

生成:

real    0m0.453s
user    0m0.826s
sys     0m0.038s

测试文档只需要稍微修改一下:

\documentclass{article}

\usepackage{datatool}

\DTLloaddbtex{\entriesdb}{entries.dbtex}

\begin{document}

\end{document}

(现在可以在命令中引用数据,例如在本例中\DTLforeach使用 的第一个参数。)\DTLloaddbtex\entriesdb

现在编译时间是:

real    0m0.180s
user    0m0.160s
sys     0m0.018s

\DTLforeach*加快文档编译时间的另一种方法是,如果您想遍历数据而不修改它,请确保使用只读。

例如,使用读写(无星号)版本:

\documentclass{article}

\usepackage{datatool}

\DTLloaddbtex{\entriesdb}{entries.dbtex}

\begin{document}

\DTLforeach{\entriesdb}{}{}

\end{document}

这需要:

real    0m11.000s
user    0m10.983s
sys     0m0.016s

使用只读(带星号的版本):

\documentclass{article}

\usepackage{datatool}

\DTLloaddbtex{\entriesdb}{entries.dbtex}

\begin{document}

\DTLforeach*{\entriesdb}{}{}

\end{document}

这需要:

real    0m1.541s
user    0m1.527s
sys     0m0.012s

总之,为了加速数据加载,可以使用以下方法datatool

  1. 确保您至少拥有 2.0 版本(尽管已经有 6 年历史了)。
  2. 首先用于datatooltk解析数据(并且如果需要,对其进行排序或过滤)并创建一个文件,用于设置用于datatool存储数据的内部宏和寄存器。

datatooltk诗句的优点和缺点\DTLloaddb

  1. CSV 文件中的任何 LaTeX 命令都\DTLloaddb需要一个反斜杠。需要datatoolktk双反斜杠。
  2. \DTLloaddb比 慢得多datatooltk
  3. \DTLloaddb无法加载条目包含换行符的 CSV 文件,但datatooltk可以。
  4. \DTLloaddb只能加载文本文件(逗号分隔、制表符分隔等),datatooltk也可以加载 XLS、ODS 并从 MySQL 提取数据。

相关内容