Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何提高INSERT语句的性能?_Python_Mysql - Fatal编程技术网

Python 如何提高INSERT语句的性能?

Python 如何提高INSERT语句的性能?,python,mysql,Python,Mysql,在如何将256x64x250值数组插入MySQL数据库方面,给了我一个良好的开端。当我真的在我的数据上尝试他的INSERT语句时,它的速度非常慢(对于一个16Mb的文件来说是6分钟) 我在阅读,它解释说这不是正确的方法,因为执行400万个单独的插入是非常低效的 现在我的数据由很多零组成(实际上超过90%),所以我加入了一个IF语句,所以我只插入大于零的值,并使用executemany(): query = """INSERT INTO `data` (frame, sensor_row, sen

在如何将256x64x250值数组插入MySQL数据库方面,给了我一个良好的开端。当我真的在我的数据上尝试他的INSERT语句时,它的速度非常慢(对于一个16Mb的文件来说是6分钟)

我在阅读,它解释说这不是正确的方法,因为执行400万个单独的插入是非常低效的

现在我的数据由很多零组成(实际上超过90%),所以我加入了一个IF语句,所以我只插入大于零的值,并使用executemany()

query = """INSERT INTO `data` (frame, sensor_row, sensor_col, value) VALUES (%s, %s, %s, %s ) """
values = []
for frames in range(nz):
    for rows in range(ny):
        for cols in range(nx):
            if data[rows,cols,frames] > 0.0:
                values.append((frames, rows, cols, data[rows,cols,frames]))           
cur.executemany(query, values)
这奇迹般地将我的处理时间减少到20秒左右,其中14秒用于创建值列表(37k行),4秒用于实际插入数据库

所以现在我想知道,如何进一步加快这个过程?因为我觉得我的循环效率非常低,必须有更好的方法。如果我需要为每只狗插入30个测量值,这仍然需要10分钟,这对于这么多的数据来说似乎太长了


以下是我的原始文件的两个版本:或。我很想尝试加载数据填充,但我不知道如何正确解析数据。

我不使用Python或mySQL,但批插入性能通常可以通过事务来提高。

如果我理解正确,executemany()会对要插入的每一行执行insert INTO查询。这可以通过创建一个包含所有值的插入查询来改进,该查询应如下所示:

INSERT INTO data
  (frame, sensor_row, sensor_col, value)
VALUES
 (1, 1, 1, 1),
 (2, 2, 2, 2),
 (3, 3, 3, 3),
 ...

python代码应该生成括号中的行值,并从中创建一个查询字符串,以最终执行一次查询。

对于循环,您可以使用列表理解而不是

values = [(frames, rows, cols, data[rows,cols,frames]) \
        for frames in range(nz) for rows in range(ny) \
        for cols in range(nx) if data[rows,cols,frames] > 0.0]           

我估计这可能会给您带来轻微的加速,比如10-20%。

在每条语句中插入多行是一种优化方法。但是,为什么需要3个循环?也许某种数据转换可能会有用

另一个选项是在插入期间禁用索引,前提是您确定不会有任何重复数据(假设表上确实有索引)。必须为每个语句更新索引,并进行检查以防止重复

在开始插入之前调用
altertable tablename DISABLE key
,完成后调用
ALTER TABLE tablename ENABLE key
,看看是否有帮助

从手册中:


改变表格。。。禁用键告诉MySQL停止更新非唯一索引。改变表格。。。然后应使用启用键重新创建缺少的索引。MySQL使用一种比逐个插入密钥快得多的特殊算法来实现这一点,因此在执行批量插入操作之前禁用密钥应该会带来相当大的加速。使用ALTERTABLE。。。除了前面提到的权限外,“禁用密钥”还需要“索引”权限。

如果数据是numpy数组,您可以尝试以下操作:

query = """INSERT INTO `data` (frame, sensor_row, sensor_col, value) VALUES (%s, %s, %s, %s ) """
values = []
rows, cols, frames = numpy.nonzero(data)
for row, col, frame in zip(rows, cols, frames):
    values.append((frame, row, col, data[row,col,frame]))

cur.executemany(query, values)


希望有帮助

插入400万行(16MB数据)的最快方法是使用加载数据填充-

因此,如果可能,生成一个csv文件,然后使用加载数据填充

希望这有帮助:)

编辑

因此,我取了一个原始数据文件rolloff.dat,编写了一个快速而肮脏的程序,将其转换为以下csv格式

从此处下载frames.dat:

帧.dat

patient_name, sample_date dd/mm/yyyy, frame_time (ms), frame 0..248, row 0..255, col 0..62, value
"Krulle (opnieuw) Krupp",04/03/2010,0.00,0,5,39,0.4
"Krulle (opnieuw) Krupp",04/03/2010,0.00,0,5,40,0.4
...
"Krulle (opnieuw) Krupp",04/03/2010,0.00,0,10,42,0.4
"Krulle (opnieuw) Krupp",04/03/2010,0.00,0,10,43,0.4
"Krulle (opnieuw) Krupp",04/03/2010,7.94,1,4,40,0.4
"Krulle (opnieuw) Krupp",04/03/2010,7.94,1,5,39,0.4
"Krulle (opnieuw) Krupp",04/03/2010,7.94,1,5,40,0.7
"Krulle (opnieuw) Krupp",04/03/2010,7.94,1,6,44,0.7
"Krulle (opnieuw) Krupp",04/03/2010,7.94,1,6,45,0.4
...
"Krulle (opnieuw) Krupp",04/03/2010,1968.25,248,241,10,0.4
"Krulle (opnieuw) Krupp",04/03/2010,1968.25,248,241,11,0.4
"Krulle (opnieuw) Krupp",04/03/2010,1968.25,248,241,12,1.1
"Krulle (opnieuw) Krupp",04/03/2010,1968.25,248,241,13,1.4
"Krulle (opnieuw) Krupp",04/03/2010,1968.25,248,241,14,0.4
该文件仅包含具有每行和列值的帧的数据,因此不包括零。已从原始文件生成24799个数据行

接下来,我创建了一个临时加载(staging)表,将frames.dat文件加载到该表中。这是一个临时表,允许您在加载到适当的生产/报告表之前操作/转换数据

drop table if exists sample_temp;
create table sample_temp
(
patient_name varchar(255) not null,
sample_date date,
frame_time decimal(6,2) not null default 0,
frame_id tinyint unsigned not null,
row_id tinyint unsigned not null,
col_id tinyint unsigned not null,
value decimal(4,1) not null default 0,
primary key (frame_id, row_id, col_id)
)
engine=innodb;
剩下的就是加载数据(注意:我使用的是windows,因此您必须编辑此脚本以使其与linux兼容-检查路径名并将“\r\n”更改为“\n”)

24K行在1.87秒内加载


希望这有帮助:)

这就是这行的作用@Alp:
values.append((frames,rows,cols,data[rows,cols,frames]))
问题是,编写这样一个列表非常慢,我不知道如何优化它可能我没有得到它,但是看到你的代码,我认为会执行以下查询:INSERT INTO data(帧,传感器行,传感器列,值)值(1,1,1,1),插入数据(帧,传感器行,传感器列,值)值(2,2,2,2),依此类推。如果我错了,请更正我。打印(查询,值)返回
('INSERT INTO
data`(帧,传感器行,传感器列,值)值(%s,%s,%s),[(0,31,45,0.40000001),(0, 31, 46, 0.40000001), (0, 32, 45, 0.40000001)然后,把我的答案看作是无用的。数据从哪里来?它是一个大的文本文件,每个框架都有一些标头,你具体想知道什么?我只是好奇长时间的读取过程是读取文件还是嵌套for循环来创建查询。什么是<代码>数据< /代码>?也许你可以获得<代码>值< /代码>。通过对
数据应用一些函数
?这可能会给您带来很大的加速。@alp&@pajton:data是一个numpy数组,它被加载到内存中,所以我猜它来自嵌套循环。如果有其他方法用索引检索所有非零值,那么我很难想象如何添加事务加入混音会提高性能…为什么我应该得到一个否决票,因为你恰好在努力思考?@Tim-我很确定否决票不是Marc投的。(也不是我。)我可能错了,但我猜是ceejayoz,他是这个帖子中唯一一个今天登记了任何反对票的参与者。我讨厌匿名反对票;选民至少应该给海报一些反馈
patient_name, sample_date dd/mm/yyyy, frame_time (ms), frame 0..248, row 0..255, col 0..62, value
"Krulle (opnieuw) Krupp",04/03/2010,0.00,0,5,39,0.4
"Krulle (opnieuw) Krupp",04/03/2010,0.00,0,5,40,0.4
...
"Krulle (opnieuw) Krupp",04/03/2010,0.00,0,10,42,0.4
"Krulle (opnieuw) Krupp",04/03/2010,0.00,0,10,43,0.4
"Krulle (opnieuw) Krupp",04/03/2010,7.94,1,4,40,0.4
"Krulle (opnieuw) Krupp",04/03/2010,7.94,1,5,39,0.4
"Krulle (opnieuw) Krupp",04/03/2010,7.94,1,5,40,0.7
"Krulle (opnieuw) Krupp",04/03/2010,7.94,1,6,44,0.7
"Krulle (opnieuw) Krupp",04/03/2010,7.94,1,6,45,0.4
...
"Krulle (opnieuw) Krupp",04/03/2010,1968.25,248,241,10,0.4
"Krulle (opnieuw) Krupp",04/03/2010,1968.25,248,241,11,0.4
"Krulle (opnieuw) Krupp",04/03/2010,1968.25,248,241,12,1.1
"Krulle (opnieuw) Krupp",04/03/2010,1968.25,248,241,13,1.4
"Krulle (opnieuw) Krupp",04/03/2010,1968.25,248,241,14,0.4
drop table if exists sample_temp;
create table sample_temp
(
patient_name varchar(255) not null,
sample_date date,
frame_time decimal(6,2) not null default 0,
frame_id tinyint unsigned not null,
row_id tinyint unsigned not null,
col_id tinyint unsigned not null,
value decimal(4,1) not null default 0,
primary key (frame_id, row_id, col_id)
)
engine=innodb;
truncate table sample_temp;

start transaction;

load data infile 'c:\\import\\frames.dat' 
into table sample_temp
fields terminated by ',' optionally enclosed by '"'
lines terminated by '\r\n'
ignore 1 lines
(
patient_name,
@sample_date,
frame_time,
frame_id,
row_id,
col_id,
value
)
set 
sample_date = str_to_date(@sample_date,'%d/%m/%Y');

commit;

Query OK, 24799 rows affected (1.87 sec)
Records: 24799  Deleted: 0  Skipped: 0  Warnings: 0