Usando o MySQL 5.6 com o mecanismo de armazenamento InnoDB para a maioria das tabelas. O tamanho do buffer pool do InnoDB é de 15 GB e os índices Innodb DB + estão em torno de 10 GB. O servidor possui 32 GB de RAM e está executando o Cent OS 7 x64.
Eu tenho uma tabela grande que contém cerca de 10 milhões de registros.
Eu recebo um arquivo de despejo atualizado de um servidor remoto a cada 24 horas. O arquivo está no formato csv. Eu não tenho controle sobre esse formato. O arquivo tem ~ 750 MB. Tentei inserir dados em uma tabela MyISAM linha por linha e demorou 35 minutos.
Eu preciso pegar apenas 3 valores por linha de 10 a 12 do arquivo e atualizá-lo no banco de dados.
Qual é a melhor maneira de conseguir algo assim?
Eu preciso fazer isso diariamente.
Atualmente, o Flow é assim:
- mysqli_begin_transaction
- Ler arquivo de despejo linha por linha
- Atualize cada registro Linha por Linha.
- mysqli_commit
As operações acima levam cerca de 30 a 40 minutos para serem concluídas. Enquanto isso, outras atualizações acontecem, o que me fornece
Tempo limite de espera de bloqueio excedido; tente reiniciar a transação
Atualização 1
carregamento de dados em nova tabela usando LOAD DATA LOCAL INFILE
. No MyISAM, 38.93 sec
enquanto no InnoDB, foram necessários 7 min e 5,21 segundos. Então eu fiz:
UPDATE table1 t1, table2 t2
SET
t1.field1 = t2.field1,
t1.field2 = t2.field2,
t1.field3 = t2.field3
WHERE t1.field10 = t2.field10
Query OK, 434914 rows affected (22 hours 14 min 47.55 sec)
Atualização 2
mesma atualização com consulta de junção
UPDATE table1 a JOIN table2 b
ON a.field1 = b.field1
SET
a.field2 = b.field2,
a.field3 = b.field3,
a.field4 = b.field4
(14 hours 56 min 46.85 sec)
Esclarecimentos de perguntas nos comentários:
- Cerca de 6% das linhas da tabela serão atualizadas pelo arquivo, mas às vezes pode chegar a 25%.
- Existem índices nos campos que estão sendo atualizados. Existem 12 índices na tabela e 8 índices incluem os campos de atualização.
- Não é necessário fazer a atualização em uma transação. Pode levar tempo, mas não mais que 24 horas. Eu estou olhando para fazê-lo em 1 hora sem bloquear a tabela inteira, pois mais tarde eu tenho que atualizar o índice de esfinge que depende dessa tabela. Não importa se as etapas demoram mais tempo, desde que o banco de dados esteja disponível para outras tarefas.
- Eu poderia modificar o formato csv em uma etapa de pré-processo. A única coisa que importa é a atualização rápida e sem travar.
- A tabela 2 é MyISAM. É a tabela recém-criada do arquivo csv usando o carregamento de dados infile. O tamanho do arquivo MYI é de 452 MB. A tabela 2 é indexada na coluna field1.
- MYD da tabela MyISAM é 663MB.
Atualização 3:
Aqui estão mais detalhes sobre as duas tabelas.
CREATE TABLE `content` (
`hash` char(40) CHARACTER SET ascii NOT NULL DEFAULT '',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`og_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`keywords` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`files_count` smallint(5) unsigned NOT NULL DEFAULT '0',
`more_files` smallint(5) unsigned NOT NULL DEFAULT '0',
`files` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`category` smallint(3) unsigned NOT NULL DEFAULT '600',
`size` bigint(19) unsigned NOT NULL DEFAULT '0',
`downloaders` int(11) NOT NULL DEFAULT '0',
`completed` int(11) NOT NULL DEFAULT '0',
`uploaders` int(11) NOT NULL DEFAULT '0',
`creation_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`upload_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`last_updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`vote_up` int(11) unsigned NOT NULL DEFAULT '0',
`vote_down` int(11) unsigned NOT NULL DEFAULT '0',
`comments_count` int(11) NOT NULL DEFAULT '0',
`imdb` int(8) unsigned NOT NULL DEFAULT '0',
`video_sample` tinyint(1) NOT NULL DEFAULT '0',
`video_quality` tinyint(2) NOT NULL DEFAULT '0',
`audio_lang` varchar(127) CHARACTER SET ascii NOT NULL DEFAULT '',
`subtitle_lang` varchar(127) CHARACTER SET ascii NOT NULL DEFAULT '',
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
`uploader` int(11) unsigned NOT NULL DEFAULT '0',
`anonymous` tinyint(1) NOT NULL DEFAULT '0',
`enabled` tinyint(1) unsigned NOT NULL DEFAULT '0',
`tfile_size` int(11) unsigned NOT NULL DEFAULT '0',
`scrape_source` tinyint(1) unsigned NOT NULL DEFAULT '0',
`record_num` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`record_num`),
UNIQUE KEY `hash` (`hash`),
KEY `uploaders` (`uploaders`),
KEY `tfile_size` (`tfile_size`),
KEY `enabled_category_upload_date_verified_` (`enabled`,`category`,`upload_date`,`verified`),
KEY `enabled_upload_date_verified_` (`enabled`,`upload_date`,`verified`),
KEY `enabled_category_verified_` (`enabled`,`category`,`verified`),
KEY `enabled_verified_` (`enabled`,`verified`),
KEY `enabled_uploader_` (`enabled`,`uploader`),
KEY `anonymous_uploader_` (`anonymous`,`uploader`),
KEY `enabled_uploaders_upload_date_` (`enabled`,`uploaders`,`upload_date`),
KEY `enabled_verified_category` (`enabled`,`verified`,`category`),
KEY `verified_enabled_category` (`verified`,`enabled`,`category`)
) ENGINE=InnoDB AUTO_INCREMENT=7551163 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=FIXED
CREATE TABLE `content_csv_dump_temp` (
`hash` char(40) CHARACTER SET ascii NOT NULL DEFAULT '',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`category_id` int(11) unsigned NOT NULL DEFAULT '0',
`uploaders` int(11) unsigned NOT NULL DEFAULT '0',
`downloaders` int(11) unsigned NOT NULL DEFAULT '0',
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`hash`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
e aqui está a consulta de atualização que atualiza a content
tabela usando dados decontent_csv_dump_temp
UPDATE content a JOIN content_csv_dump_temp b
ON a.hash = b.hash
SET
a.uploaders = b.uploaders,
a.downloaders = b.downloaders,
a.verified = b.verified
atualização 4:
todos os testes acima foram feitos na máquina de teste., mas agora fiz os mesmos testes na máquina de produção e as consultas são muito rápidas.
mysql> UPDATE content_test a JOIN content_csv_dump_temp b
-> ON a.hash = b.hash
-> SET
-> a.uploaders = b.uploaders,
-> a.downloaders = b.downloaders,
-> a.verified = b.verified;
Query OK, 2673528 rows affected (7 min 50.42 sec)
Rows matched: 7044818 Changed: 2673528 Warnings: 0
Eu peço desculpas pelo meu erro. É melhor usar a junção em vez de cada atualização de registro. agora estou tentando melhorar o mpre usando o índice sugerido por rick_james, será atualizado assim que a marcação de banco de dados for concluída.
UPDATEs
. Diga-nos exatamente como é a declaração direta para atualizar a tabela a partir dos dados csv. Então nós podemos ser capazes de ajudá-lo a desenvolver uma técnica que atenda às suas necessidades.
update
, e verifique questão atualizado, obrigado.
INDEX(field2, field3, field4)
(em qualquer ordem)? Por favor, mostre-nosSHOW CREATE TABLE
.