0

我有 5 个要导入 MySQL/MariaDB 数据库的文本字段。但是有两个问题:

(1) 文件非常大:0.5 GB 到 10 GB
(2) 所有相关键有 40 个字符

第(1)点我必须接受它,我不能改变它。第2点是我关心的。网上有很多建议。例如,将枚举用于 varchar 或使用数字代理。将代理键添加到表中没有问题。但是必须将相同的代理键添加到其他表中。这就是我坚持的地方。

这里是有关文件/表的具体信息:

  • invoice有 3 列和 20 Mio 行:

    • 具有不同值的 invoice_id(主键)= 行数
    • 具有 4,000 个不同值的 praxis_id
    • 具有 4 个 Mio 不同值的患者 ID,所有列都是 CHAR(40),并且具有 40 的固定长度。
  • 诊断有 3 列和 25 Mio 行:

    • invoice_id CHAR(40) 1.4 Mio distinct id
    • 诊断类型
    • 诊断代码
  • 患者有 5 列和 5 Mio 行:

    • patient_id CHAR(40) 不唯一(4 Mio distinct pat_id)
    • praxis_id CHAR(40)
    • 出生年份、性别等

例如,我想将发票与诊断和患者一起加入。索引键是有意义的。一种方法是将 invoice.invoice_id 定义为主键,对于表 invoice 中的所有其他键,我将添加一个索引。与表诊断(invoice_id with INDEX)和患者(patient_id 作为主键)相同。
问题是使用以下命令将 invoice.invoice_id 定义为主键需要很长时间:

ALTER TABLE invoice_id ADD PRIMARY KEY(invoice_id);

一小时后,我终止了该过程。我认为性能问题是由表 invoice 中 invoice_id 的数据类型引起的。一个想法可能是在加载文本文件时添加一个自动递增代理键 invoice_id_surr。但是,如果我想加入表诊断,问题仍然存在,因为我必须加入表诊断的 invoice_id,它没有代理键 invoice_id_surr 作为外键。我可以在 diagnostic.invoice_id 上添加一个索引,但随后我失去了在表格发票上拥有代理键​​的优势。

我会对如何处理这个问题的策略感兴趣:几个已经存在的表可以连接在一起,但键是 CHAR(40) 并且没有索引。

感谢帮助。


更新 1:表格规范
- 键有 40 个字符 [0-9][AZ]
- 这些表格不再更改(无插入)

-- invoice_id is primary key (unique)
-- patient_id and praxis id for foreign key and not unique in this table
CREATE TABLE invoice (
  invoice_id             CHAR(40) DEFAULT NULL
, praxis_id              CHAR(40) DEFAULT NULL
, patient_id             CHAR(40) DEFAULT NULL
, PRIMARY KEY (invoice_id2)
) ENGINE = InnoDB
;  

LOAD DATA LOCAL INFILE 'C:/data/invoice.txt'
INTO TABLE invoice
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\r\n'
IGNORE 1 LINES
;

-- invoice_id is not unique in this table
CREATE TABLE diagnose (
  invoice_id             CHAR(40)    DEFAULT NULL
, diagnose_katalog       VARCHAR(20) DEFAULT NULL
, diagnose_code          VARCHAR(20) DEFAULT NULL
) ENGINE = InnoDB
;
-- patient_id is not unique in this table since since patient may change praxis
CREATE TABLE patient (
  patient_id             CHAR(40)    DEFAULT NULL
, praxis_id              CHAR(40)    DEFAULT NULL
, sex                    CHAR(1)     DEFAULT NULL
, birth_year             SMALLINT UNSIGNED DEFAULT NULL
, zip_code               VARCHAR(20) DEFAULT NULL
) ENGINE = InnoDB
;
4

3 回答 3

1

出于各种原因,您应该避免在数据库中使用自然键作为主键,通过谷歌搜索很容易找到。

另外,“给定表格”是什么意思?您不应该坚持在文本文件和数据库表之间建立一一对应的关系。相反,您应该以最适合您需求的方式设计表格。争取正常化。

例如,您说patient_idpatient“表”中(您的意思是文件,对吗?)不是唯一的。显然,您需要一张患者独特的表格;所以创建一个具有不同patient_id及其属性的表。patient_id应该是该表上的唯一键,但生成一个数字代理项(例如 auto_increment 字段)作为该表中的主键。之后,例如,创建一个praxis表,其中praxis_id作为唯一键和主键的数字代理。然后,您可以 根据多对多关系连接patient并使用第三个表。praxis这样您就可以标准化您的数据库:具有其属性的患者始终是单个patient表中的单行;而现在你有同一个病人多次输入你当前patient文件/表,迟早会给你带来麻烦。

于 2015-06-09T07:31:09.823 回答
1

你真的有CHAR(40),不是VARCHAR(40)吗?值总是 40 个字符吗?是表CHARACTER SET utf8吗?

CHAR(40) utf8总是占用 120 个字节。如果您在这样的字段中存储“Z”,它仍然需要 120 个字节,而不仅仅是 1。即使您正在导入 40 个字符,声明它VARCHAR会在加载时修剪尾随空白。

至少,我会做

ALTER TABLE foo
    MODIFY col1 VARCHAR(40) ...,  -- the "..." is other options for the col
    MODIFY col2 VARCHAR(40) ...,
    ...;

这可能会对“点(1)”有很大帮助。让一切变得更快。(警告:完成 ALTER 需要很长时间。)

“自然”主键并不邪恶。但在适当的地方使用它们。在您的情况下,invoice_id出于业务原因需要是唯一的,对吗?多久了?作为PK应该不错吧。

在你尝试做之前,你桌子上有什么钥匙ALTER?最初构建表时,您应该至少有适当的PRIMARY KEY位置。(但现在为时已晚,我猜。)

请提供SHOW CREATE TABLE每张桌子——我不得不做出太多猜测。

添加代理 ( AUTO_INCREMENT) 键为所有查找添加了一个间接级别;这可能会减慢一些速度SELECTs(除了需要对许多 SELECTs进行更改)。

向表中添加二级索引时,应基于对SELECT您拥有的语句有用的内容。我在我的索引食谱中讨论了这一点。在此提供SELECTs进一步讨论。不要盲目地为每一列添加索引。

听起来invoice_id应该是PRIMARY KEYforinvoiceINDEXin diagnose

如果重新加载数据可行,请声明字段VARCHAR、 notCHAR和 have PRIMARY KEY(invoice_id)in invoice

于 2015-06-10T15:53:38.577 回答
0

我自己回答我的问题。发布此帖子的原因是我提交了查询,例如定义一个主键,ALTER TABLE ...并且该过程在几个小时后没有停止。正如@zgguv 提到的,持续时间似乎不合理。我停止了查询并重新启动(有时在第三次之后),并且该过程在几分钟后完成(大约 10 分钟)。我不知道为什么有时查询会挂断。直到现在这从未发生在我身上,但我使用的桌子要小得多。吸取的教训是:

  • 长字符串键应替换为数字键以加快选择速度。

  • 分别替换大小为 10 GB(文本表)的表的字符串键,20 个 Mio 行号是可行的(您只需拉自己的头发一次)。索引字符串键之间的连接大约需要 10 分钟。

  • 如果查询的持续时间超过 30'(挂断),则停止它并重试。很高兴知道为什么会发生这种情况(InnoDB,MyISAM,HeidiSQL,...),但这是另一个问题。

@zgguv 感谢您的支持和耐心。

于 2015-06-10T14:10:04.150 回答