- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
对于 this project ,我打算制作一个 web 版本,现在正在制作一个 PostgreSQL (9.x) 后端,webapp 将从中查询。
现在,跟踪器生成一个包含两个 CSV 的 zip 文件,在运行时将其加载到 H2 数据库中,其模式是这样的(是的,我知道 SQL 可以写得稍微更好):
create table matchers (
id integer not null,
class_name varchar(255) not null,
matcher_type varchar(30) not null,
name varchar(1024) not null
);
alter table matchers add primary key(id);
create table nodes (
id integer not null,
parent_id integer not null,
level integer not null,
success integer not null,
matcher_id integer not null,
start_index integer not null,
end_index integer not null,
time bigint not null
);
alter table nodes add primary key(id);
alter table nodes add foreign key (matcher_id) references matchers(id);
create index nodes_parent_id on nodes(parent_id);
create index nodes_indices on nodes(start_index, end_index);
现在,由于 PostgreSQL 数据库将能够处理多个跟踪,我不得不再添加一张表; PostgreSQL 后端的架构看起来像这样(也低于平均 SQL 警报;此外,在 parse_info
表中,content
列包含已解析文件的全文,在 zip 文件中单独存储):
create table parse_info (
id uuid primary key,
date timestamp not null,
content text not null
);
create table matchers (
parse_info_id uuid references parse_info(id),
id integer not null,
class_name varchar(255) not null,
matcher_type varchar(30) not null,
name varchar(1024) not null,
unique (parse_info_id, id)
);
create table nodes (
parse_info_id uuid references parse_info(id),
id integer not null,
parent_id integer not null,
level integer not null,
success integer not null,
matcher_id integer not null,
start_index integer not null,
end_index integer not null,
time bigint not null,
unique (parse_info_id, id)
);
alter table nodes add foreign key (parse_info_id, matcher_id)
references matchers(parse_info_id, id);
create index nodes_parent_id on nodes(parent_id);
create index nodes_indices on nodes(start_index, end_index);
现在,我正在做的是获取现有的 zip 文件并将它们插入到 postgresql 数据库中;我正在使用 JooQ 及其 CSV loading API .
过程有点复杂...以下是当前的步骤:
parse_info
表中;代码如下:
public final class Zip2Db2
{
private static final Pattern SEMICOLON = Pattern.compile(";");
private static final Function<String, String> CSV_ESCAPE
= TraceCsvEscaper.ESCAPER::apply;
// Paths in the zip to the different components
private static final String INFO_PATH = "/info.csv";
private static final String INPUT_PATH = "/input.txt";
private static final String MATCHERS_PATH = "/matchers.csv";
private static final String NODES_PATH = "/nodes.csv";
// Fields to use for matchers zip insertion
private static final List<Field<?>> MATCHERS_FIELDS = Arrays.asList(
MATCHERS.PARSE_INFO_ID, MATCHERS.ID, MATCHERS.CLASS_NAME,
MATCHERS.MATCHER_TYPE, MATCHERS.NAME
);
// Fields to use for nodes zip insertion
private static final List<Field<?>> NODES_FIELDS = Arrays.asList(
NODES.PARSE_INFO_ID, NODES.PARENT_ID, NODES.ID, NODES.LEVEL,
NODES.SUCCESS, NODES.MATCHER_ID, NODES.START_INDEX, NODES.END_INDEX,
NODES.TIME
);
private final FileSystem fs;
private final DSLContext jooq;
private final UUID uuid;
private final Path tmpdir;
public Zip2Db2(final FileSystem fs, final DSLContext jooq, final UUID uuid)
throws IOException
{
this.fs = fs;
this.jooq = jooq;
this.uuid = uuid;
tmpdir = Files.createTempDirectory("zip2db");
}
public void removeTmpdir()
throws IOException
{
// From java7-fs-more (https://github.com/fge/java7-fs-more)
MoreFiles.deleteRecursive(tmpdir, RecursionMode.KEEP_GOING);
}
public void run()
{
time(this::generateMatchersCsv, "Generate matchers CSV");
time(this::generateNodesCsv, "Generate nodes CSV");
time(this::writeInfo, "Write info record");
time(this::writeMatchers, "Write matchers");
time(this::writeNodes, "Write nodes");
}
private void generateMatchersCsv()
throws IOException
{
final Path src = fs.getPath(MATCHERS_PATH);
final Path dst = tmpdir.resolve("matchers.csv");
try (
final Stream<String> lines = Files.lines(src);
final BufferedWriter writer = Files.newBufferedWriter(dst,
StandardOpenOption.CREATE_NEW);
) {
// Throwing below is from throwing-lambdas
// (https://github.com/fge/throwing-lambdas)
lines.map(this::toMatchersLine)
.forEach(Throwing.consumer(writer::write));
}
}
private String toMatchersLine(final String input)
{
final List<String> parts = new ArrayList<>();
parts.add('"' + uuid.toString() + '"');
Arrays.stream(SEMICOLON.split(input, 4))
.map(s -> '"' + CSV_ESCAPE.apply(s) + '"')
.forEach(parts::add);
return String.join(";", parts) + '\n';
}
private void generateNodesCsv()
throws IOException
{
final Path src = fs.getPath(NODES_PATH);
final Path dst = tmpdir.resolve("nodes.csv");
try (
final Stream<String> lines = Files.lines(src);
final BufferedWriter writer = Files.newBufferedWriter(dst,
StandardOpenOption.CREATE_NEW);
) {
lines.map(this::toNodesLine)
.forEach(Throwing.consumer(writer::write));
}
}
private String toNodesLine(final String input)
{
final List<String> parts = new ArrayList<>();
parts.add('"' + uuid.toString() + '"');
SEMICOLON.splitAsStream(input)
.map(s -> '"' + CSV_ESCAPE.apply(s) + '"')
.forEach(parts::add);
return String.join(";", parts) + '\n';
}
private void writeInfo()
throws IOException
{
final Path path = fs.getPath(INFO_PATH);
try (
final BufferedReader reader = Files.newBufferedReader(path);
) {
final String[] elements = SEMICOLON.split(reader.readLine());
final long epoch = Long.parseLong(elements[0]);
final Instant instant = Instant.ofEpochMilli(epoch);
final ZoneId zone = ZoneId.systemDefault();
final LocalDateTime time = LocalDateTime.ofInstant(instant, zone);
final ParseInfoRecord record = jooq.newRecord(PARSE_INFO);
record.setId(uuid);
record.setContent(loadText());
record.setDate(Timestamp.valueOf(time));
record.insert();
}
}
private String loadText()
throws IOException
{
final Path path = fs.getPath(INPUT_PATH);
try (
final BufferedReader reader = Files.newBufferedReader(path);
) {
return CharStreams.toString(reader);
}
}
private void writeMatchers()
throws IOException
{
final Path path = tmpdir.resolve("matchers.csv");
try (
final BufferedReader reader = Files.newBufferedReader(path);
) {
jooq.loadInto(MATCHERS)
.onErrorAbort()
.loadCSV(reader)
.fields(MATCHERS_FIELDS)
.separator(';')
.execute();
}
}
private void writeNodes()
throws IOException
{
final Path path = tmpdir.resolve("nodes.csv");
try (
final BufferedReader reader = Files.newBufferedReader(path);
) {
jooq.loadInto(NODES)
.onErrorAbort()
.loadCSV(reader)
.fields(NODES_FIELDS)
.separator(';')
.execute();
}
}
private void time(final ThrowingRunnable runnable, final String description)
{
System.out.println(description + ": start");
final Stopwatch stopwatch = Stopwatch.createStarted();
runnable.run();
System.out.println(description + ": done (" + stopwatch.stop() + ')');
}
public static void main(final String... args)
throws IOException
{
if (args.length != 1) {
System.err.println("missing zip argument");
System.exit(2);
}
final Path zip = Paths.get(args[0]).toRealPath();
final UUID uuid = UUID.randomUUID();
final DSLContext jooq = PostgresqlTraceDbFactory.defaultFactory()
.getJooq();
try (
final FileSystem fs = MoreFileSystems.openZip(zip, true);
) {
final Zip2Db2 zip2Db = new Zip2Db2(fs, jooq, uuid);
try {
zip2Db.run();
} finally {
zip2Db.removeTmpdir();
}
}
}
}
现在,这是我的第一个问题......它比加载到 H2 慢得多。以下是包含 620 个匹配器和 45746 个节点的 CSV 的时序:
Generate matchers CSV: start
Generate matchers CSV: done (45.26 ms)
Generate nodes CSV: start
Generate nodes CSV: done (573.2 ms)
Write info record: start
Write info record: done (311.1 ms)
Write matchers: start
Write matchers: done (4.192 s)
Write nodes: start
Write nodes: done (22.64 s)
给予或接受,忘记有关编写专门 CSV 的部分(见下文),即 25 秒。将其加载到基于磁盘的动态 H2 数据库中只需 不到 5 秒!
我遇到的另一个问题是我必须编写专用的 CSV;似乎 CSV 加载 API 在接受的内容上并不是很灵活,例如,我不得不转这一行:
328;SequenceMatcher;COMPOSITE;token
进入这个:
"some-randome-uuid-here";"328";"SequenceMatcher";"COMPOSITE";"token"
但我最大的问题实际上是这个 zip 非常小。例如,我有一个 zip 不是 620,而是 1532 个匹配器,不是 45746 个节点,而是超过 3400 万个节点;即使我们忽略 CSV 生成时间(原始节点 CSV 为 1.2 GiB),由于 H2 注入(inject)需要 20 分钟,将其乘以 5 会得到 1 小时 30 分以南某个点的时间,这很多!
总而言之,目前这个过程效率很低......
现在,为 PostgreSQL 辩护:
jdbc:h2:/path/to/db;LOG=0;LOCK_MODE=0;UNDO_LOG=0;CACHE_SIZE=131072
。尽管如此,插入时间的这种差异似乎有点过分,但我确信它可以更好。但我不知道从哪里开始。
另外,我知道 PostgreSQL 有一个专门的机制来从 CSV 加载,但这里的 CSV 是在一个 zip 文件中开始的,我真的很想避免像我现在这样创建一个专用的 CSV做...理想情况下,我想直接从 zip 中逐行读取(这是我为 H2 注入(inject)所做的),转换行并写入 PostgreSQL 模式。
最后,我还知道我目前没有在插入前禁用对 PostgreSQL 模式的约束;我还没有尝试过这个(它会有所作为吗?)。
那么,您建议我如何提高性能?
最佳答案
从 CSV 文件批量插入 PostgreSQL 的最快方法是使用 Copy . COPY 命令针对插入大量行进行了优化。
对于 Java,您可以使用 Copy implementation for PostgreSQL JDBC driver
这里有一个很好的小例子来说明如何使用它:how to copy a data from file to PostgreSQL using JDBC?
如果你有一个带有标题的 CSV,你会想要运行一个类似于这样的命令:
\COPY mytable FROM '/tmp/mydata.csv' DELIMITER ';' CSV 标题
将大量数据添加到现有表时的另一个性能提升是删除索引,插入数据,然后重新创建索引。
关于java - 从 CSV 加载时的 PostgreSQL/JooQ 批量插入性能问题;我如何改进流程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29749615/
我想要显示正在加载的 .gif,直到所有内容都已加载,包括嵌入的 iframe。但是,目前加载 gif 会在除 iframe 之外的所有内容都已加载后消失。我怎样才能让它等到 iframe 也加载完毕
首先,这是我第一次接触 Angular。 我想要实现的是,我有一个通知列表,我必须以某种方式限制 limitTo,因此元素被限制为三个,在我单击按钮后,其余的应该加载。 我不明白该怎么做: 设置“ V
我正在尝试在我的设备上运行这个非常简单的应用程序(使用 map API V2),并且出于某种原因尝试使用 MapView 时: 使用 java 文件: public class MainMap e
我正在使用 Python 2.6、Excel 2007 Professional 和最新版本的 PyXLL。在 PyXLL 中加载具有 import scipy 抛出异常,模块未加载。有没有人能够在
我想做这个: 创建并打包原始游戏。然后我想根据原始游戏中的蓝图创建具有新网格/声音/动画和蓝图的其他 PAK 文件。原始游戏不应该知道有关其他网格/动画/等的任何信息。因此,我需要在原始游戏中使用 A
**摘要:**在java项目中经常会使用到配置文件,这里就介绍几种加载配置文件的方法。 本文分享自华为云社区《【Java】读取/加载 properties配置文件的几种方法》,作者:Copy工程师。
在 Groovy 脚本中是否可以执行条件导入语句? if (test){ import this.package.class } else { import that.package.
我正在使用 NVidia 视觉分析器(来自 CUDA 5.0 beta 版本的基于 eclipse 的版本)和 Fermi 板,我不了解其中两个性能指标: 全局加载/存储效率表示实际内存事务数与请求事
有没有办法在通过 routeProvider 加载特定 View 时清除 Angular JS 存储的历史记录? ? 我正在使用 Angular 创建一个公共(public)安装,并且历史会积累很多,
使用 Xcode 4.2,在我的应用程序中, View 加载由 segue 事件触发。 在 View Controller 中首先调用什么方法? -(void) viewWillAppear:(BOO
我在某些Django模型中使用JSONField,并希望将此数据从Oracle迁移到Postgres。 到目前为止,当使用Django的dumpdata和loaddata命令时,我仍然没有运气来保持J
创建 Nib 时,我需要创建两种类型:WindowNib 或 ViewNib。我看到的区别是,窗口 Nib 有一个窗口和一个 View 。 如何将 View Nib 加载到另一个窗口中?我是否必须创建
我想将多个env.variables转换为静态结构。 我可以手动进行: Env { is_development: env::var("IS_DEVELOPMENT")
正如我从一个测试用例中看到的:https://godbolt.org/z/K477q1 生成的程序集加载/存储原子松弛与普通变量相同:ldr 和 str 那么,宽松的原子变量和普通变量之间有什么区别吗
我有一个重定向到外部网站的按钮/链接,但是外部网站需要一些时间来加载。所以我想添加一个加载屏幕,以便外部页面在显示之前完全加载。我无法控制外部网站,并且外部网站具有同源策略,因此我无法在 iFrame
我正在尝试为我的应用程序开发一个Dockerfile,该文件在初始化后加载大量环境变量。不知何故,当我稍后执行以下命令时,这些变量是不可用的: docker exec -it container_na
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我刚刚遇到一个问题,我有一个带有一些不同选项的选择标签。 现在我想检查用户选择了哪些选项。 然后我想将一个新的 html 文件加载到该网站(取决于用户选中的选项)宽度 javascript,我该怎么做
我知道两种保存/加载应用程序设置的方法: 使用PersistentStore 使用文件系统(存储,因为 SDCard 是可选的) 我想知道您使用应用程序设置的做法是什么? 使用 PersistentS
我开始使用 Vulkan 时偶然发现了我的第一个问题。尝试创建调试报告回调时(验证层和调试扩展在我的英特尔 hd vulkan 驱动程序上可用,至少它是这么说的),它没有告诉我 vkCreateDeb
我是一名优秀的程序员,十分优秀!