我正在使用该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
:
- 确保您至少拥有 2.0 版本(尽管已经有 6 年历史了)。
- 首先用于
datatooltk
解析数据(并且如果需要,对其进行排序或过滤)并创建一个文件,用于设置用于datatool
存储数据的内部宏和寄存器。
datatooltk
诗句的优点和缺点\DTLloaddb
:
- CSV 文件中的任何 LaTeX 命令都
\DTLloaddb
需要一个反斜杠。需要datatoolktk
双反斜杠。 \DTLloaddb
比 慢得多datatooltk
。\DTLloaddb
无法加载条目包含换行符的 CSV 文件,但datatooltk
可以。\DTLloaddb
只能加载文本文件(逗号分隔、制表符分隔等),datatooltk
也可以加载 XLS、ODS 并从 MySQL 提取数据。