MySQL - 如何逐位执行事务,而不是一次执行(如循环)

时间:2016-12-03 00:14:35

标签: mysql sql

我需要传输数据(我需要的列n.inchi,n.info,n.accessions,n.chebiid从一个表到另一个表,两个表都有超过20,000行(heroku_chemical_chemical有50,000个,这就是表I我传输的数据to)。

我尝试了这个查询:

UPDATE heroku_chemical_chemical AS h, new_compounds_filtered AS n
SET 
h.inchi_identifier=n.inchi,
h.info=n.info,
h.accessions=n.accessions,
h.chebi_id=n.chebiid
WHERE h.name = n.name 
AND (h.inchi_identifier = '' OR h.inchi_identifier IS NULL); 

基本上,表1中显示的化学名称(heroku_chemical_chemical)可能存在于表2中,如果是,我需要从表2中获取该化学品的数据。如果h.inchi_identifier中有数据,那么我就知道化学品已经完成了。问题是查询需要花费很长时间才能执行,我让它在一夜之间运行,但是第二天早上它仍然没有完成,所以我不得不取消它。自交易以来,没有任何转移。如果它是逐位执行传输,那么它将起作用。

我可以将其添加到查询中:

AND n.id BETWEEN 1 AND 500

将查询限制为500行(从我传输数据的第二个表中)以小块形式执行,但是我手动必须继续使用{{1的不同值重新运行查询子句。它也很慢。我更喜欢在纯SQL中执行此操作,而不是设置PHP脚本。

有没有办法在数据进行时插入数据,而不是等到整个事务完成?另外,有没有办法更快地完成这项工作?

见表定义:

heroku_chemical_chemical

BETWEEN

new_compounds_filtered

CREATE TABLE `heroku_chemical_chemical` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` text COLLATE utf8mb4_unicode_ci,
  `synonyms` text COLLATE utf8mb4_unicode_ci,
  `associated_from` text COLLATE utf8mb4_unicode_ci,
  `category_associated_from` text COLLATE utf8mb4_unicode_ci,
  `chemical_number` text COLLATE utf8mb4_unicode_ci,
  `parent_chemical_numbers` text COLLATE utf8mb4_unicode_ci,
  `category_id` text COLLATE utf8mb4_unicode_ci,
  `slug` text COLLATE utf8mb4_unicode_ci,
  `cas_rn` text COLLATE utf8mb4_unicode_ci,
  `definition` text COLLATE utf8mb4_unicode_ci,
  `drug_bank_ids` text COLLATE utf8mb4_unicode_ci,
  `foodb_id` text COLLATE utf8mb4_unicode_ci,
  `itis_id` text COLLATE utf8mb4_unicode_ci,
  `name_scientific` text COLLATE utf8mb4_unicode_ci,
  `picture_content_type` text COLLATE utf8mb4_unicode_ci,
  `picture_file_name` text COLLATE utf8mb4_unicode_ci,
  `picture_file_size` text COLLATE utf8mb4_unicode_ci,
  `wikipedia_id` text COLLATE utf8mb4_unicode_ci,
  `actor_id` text COLLATE utf8mb4_unicode_ci,
  `bio_cyc_id` text COLLATE utf8mb4_unicode_ci,
  `chebi_id` text COLLATE utf8mb4_unicode_ci,
  `chem_spider_id` text COLLATE utf8mb4_unicode_ci,
  `chembl_id` text COLLATE utf8mb4_unicode_ci,
  `ctd_id` text COLLATE utf8mb4_unicode_ci,
  `hmdb_id` text COLLATE utf8mb4_unicode_ci,
  `inchi_identifier` text COLLATE utf8mb4_unicode_ci,
  `inchi_key` text COLLATE utf8mb4_unicode_ci,
  `kegg_compound_id` text COLLATE utf8mb4_unicode_ci,
  `omim_id` text COLLATE utf8mb4_unicode_ci,
  `pdb_id` text COLLATE utf8mb4_unicode_ci,
  `pubchem_compound_id` text COLLATE utf8mb4_unicode_ci,
  `stitch_di` text COLLATE utf8mb4_unicode_ci,
  `t3db_id` text COLLATE utf8mb4_unicode_ci,
  `uni_prot_id` text COLLATE utf8mb4_unicode_ci,
  `iupac_name` text COLLATE utf8mb4_unicode_ci,
  `formula` text COLLATE utf8mb4_unicode_ci,
  `smiles` text COLLATE utf8mb4_unicode_ci,
  `chemspider_id` text COLLATE utf8mb4_unicode_ci,
  `molecular_weight` text COLLATE utf8mb4_unicode_ci,
  `accessions` text COLLATE utf8mb4_unicode_ci,
  `chebi_info` text COLLATE utf8mb4_unicode_ci,
  `chebi_name` text COLLATE utf8mb4_unicode_ci,
  `compound_type` text COLLATE utf8mb4_unicode_ci,
  PRIMARY KEY (`id`)
) 
ENGINE=InnoDB 
AUTO_INCREMENT=379336 
DEFAULT CHARSET=utf8mb4 
COLLATE=utf8mb4_unicode_ci;

更新

所以我正在运行一个新查询,需要将ID(被索引)加载到关系表的列中。

CREATE TABLE `new_compounds_filtered` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` text COLLATE utf8mb4_unicode_ci,
  `chebiid` text COLLATE utf8mb4_unicode_ci,
  `info` text COLLATE utf8mb4_unicode_ci,
  `smiles` text COLLATE utf8mb4_unicode_ci,
  `inchi` text COLLATE utf8mb4_unicode_ci,
  `inchikey` text COLLATE utf8mb4_unicode_ci,
  `parent_id` text COLLATE utf8mb4_unicode_ci,
  `accessions` text COLLATE utf8mb4_unicode_ci,
  `synonyms` text COLLATE utf8mb4_unicode_ci,
  PRIMARY KEY (`id`)
) 
ENGINE=InnoDB 
AUTO_INCREMENT=85432 
DEFAULT CHARSET=utf8mb4 
COLLATE=utf8mb4_unicode_ci ;

同样的问题,查询似乎没有完成。我无法在H1.foodb_id上添加唯一索引,因为表中只有大约5%的化学品具有FooDB ID。所以我遇到了同样的问题。 O2.compound_id是未编制索引的,因为它的所有字段现在都是空白的,除非我在每个字段中插入临时唯一编号,否则我无法对它们编制索引。

下面是UPDATE chemical_organism_relations AS O2, heroku_chemical_chemical AS H1 SET O2.compound_id = H1.id, O2.substance_type = 'compound' WHERE O2.foodb_compound_id = H1.foodb_id; 表中的内容:

enter image description here

我一直在寻找一种方法来跟踪查询进度。我想知道的一件事是这些专栏意味着什么: enter image description here

有没有办法看到幕后发生的事情?如果我能看到服务器正在做什么以及它在运行查询时取得了多少进展,那么我就知道查询是否会完成,但是现在我不知道它是否崩溃或者是否发生了什么。

我刚刚运行了一个非常简单的查询:

  

的MySQL> UPDATE chemical_organism_relations SET substance_type =   '化合物&#39 ;;查询OK,受影响的740672行(1分钟2.95秒)行   匹配:740672更改:740672警告:0

74000,但需要一分钟来处理一个不涉及其他表的简单更新查询。

我的查询存在大问题 在我将它与主线程合并之前,有人评论了一个答案,他们说是因为:

performance_schema.events_statements_current

我的查询存在很大问题。我不小心发布了错误的查询,但我现在发布了正确的查询,查询仍有问题吗?

1 个答案:

答案 0 :(得分:1)

如上所述,50k线真的没什么:在1M之后事情变得严重,你需要思考一下,如果你想超过10M而没有问题......

除此之外,当你做一个大事务时,你需要有点小心,innoDB并没有真正配置为默认值,并且会有一些RAM& I.O磁盘瓶颈(如果必须定期进行,请查看MySQL transaction size - how big is too big?,一些数据库调优可能是一个好主意)

无论如何,让我们从一些基础知识开始:

WHERE 
    h.name = n.name 
    AND (
        h.inchi_identifier = '' 
        OR h.inchi_identifier IS NULL
    ); 

大查询中WHERE之后的每个字段应该强制有一个索引如果你不能放一个,那么你的数据库架构是坏的(如果你在0.01中那么可能是99.99%) %你已经知道为什么了)

What Index you ask ?嗯,你有一些选择,我只会解释最有用的一些:

PRIMARY KEY

是的,这是第一个也是最重要的。你只能有一个表,它也是一个UNIQUE约束,如果你有和标识符字段,使用它作为你的PK,不需要添加专用的id int auto_increment

UNIQUE INDEX

如果您的桌子上已经有PK,但在另一个字段中有一些唯一的ID,UNIQUE INDEX可以帮助您快速阅读/更新此字段(但会减慢插入,因为它会检查唯一性)

INDEX,多遍

“但我已经有PK了,我的字段不是唯一的,所以没有索引?”

在大多数数据库中通常都是这种情况,你有一个外国人密钥(1-N)的字段,你会在其上做很多JOINWHERE,但不能使用一个之前的指数,然后来了魔术:

INDEX允许您加快查询速度,即使字段中存在重复项或null

它会使INSERT慢一点,但你将获得SELECT,UPDATE,DELETE,WHERE,JOIN和这个字段。

综合指数

这是制作索引的更多方法。这比以前的更复杂,因为如果你想要使用这个查询,你真的需要了解你的查询是如何工作的。

[以书面形式]

回到你的查询,这可能是你应该做的(记住它可以减慢一些操作,并且可能需要一些时间来构建):

    -- speed the null / "" detection
CREATE INDEX idx_hcc_inchi_id_1char 
    ON heroku_chemical_chemical (inchi_identifier(1));

    -- uniqueness of name
CREATE UNIQUE INDEX idx_hcc_name_u 
    ON heroku_chemical_chemical (name);
CREATE UNIQUE INDEX idx_ncf_name_u 
    ON new_compounds_filtered (name);

对于问题的第二部分:

  

“我不能在UNIQUE INDEX上放foodb_id,因为只有5%的行有FooDB_ID”

不是问题:

  • ALTER TABLE column allow null(如果我查看您的架构已经没问题了)
  • 将空字符串''更新为NULLUPDATE table SET column=NULL WHERE column='';
  • 在列上添加UNIQUE INDEX,因为
  • 允许NULL