我想问一下,如果在for循环中执行commit,下面的语句会给出一个磁盘I / O消息?如果在for循环外执行commit,则不会出错。
错误讯息:
Traceback (most recent call last):
File "D:\Dropbox\Public\EBOOK\Python\Learn\SQLITE_DB\ParsedJSON\ParsedJSON.py"
, line 71, in <module>
conn.commit()
sqlite3.OperationalError: disk I/O error
代码
for entry in json_data:
name = entry[0];
title = entry[1];
role = entry[2];
print name, title, role
cur.execute('''INSERT OR IGNORE INTO User (name)
VALUES ( ? )''', ( name, ) )
cur.execute('SELECT id FROM User WHERE name = ? ', (name, ))
user_id = cur.fetchone()[0]
cur.execute('''INSERT OR IGNORE INTO Course (title)
VALUES ( ? )''', ( title, ) )
cur.execute('SELECT id FROM Course WHERE title = ? ', (title, ))
course_id = cur.fetchone()[0]
cur.execute('''INSERT OR REPLACE INTO Member
(user_id, course_id, role) VALUES ( ?, ?, ? )''',
( user_id, course_id, role ) )
conn.commit()
完整代码
import json
import sqlite3
conn = sqlite3.connect('rosterdb.sqlite')
cur = conn.cursor()
# Do some setup
cur.executescript('''
DROP TABLE IF EXISTS User;
DROP TABLE IF EXISTS Member;
DROP TABLE IF EXISTS Course;
CREATE TABLE User (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
name TEXT UNIQUE
);
CREATE TABLE Course (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
title TEXT UNIQUE
);
CREATE TABLE Member (
user_id INTEGER,
course_id INTEGER,
role INTEGER,
PRIMARY KEY (user_id, course_id)
)
''')
fname = raw_input('Enter file name: ')
if ( len(fname) < 1 ) : fname = 'roster_data.json'
str_data = open(fname).read()
json_data = json.loads(str_data)
for entry in json_data:
name = entry[0];
title = entry[1];
role = entry[2];
print name, title, role
cur.execute('''INSERT OR IGNORE INTO User (name)
VALUES ( ? )''', ( name, ) )
cur.execute('SELECT id FROM User WHERE name = ? ', (name, ))
user_id = cur.fetchone()[0]
cur.execute('''INSERT OR IGNORE INTO Course (title)
VALUES ( ? )''', ( title, ) )
cur.execute('SELECT id FROM Course WHERE title = ? ', (title, ))
course_id = cur.fetchone()[0]
cur.execute('''INSERT OR REPLACE INTO Member
(user_id, course_id, role) VALUES ( ?, ?, ? )''',
( user_id, course_id, role ) )
conn.commit()
答案 0 :(得分:1)
我很好奇提交I / O实际上有多大的影响,所以我运行了一些测试,其中一些模拟的JSON符合以下格式:
{
"folks": [
{
"name": "Foghorn Leghorn",
"title": "Principal",
"role": "Administration"
}
]
}
我的结果很有启发性。这些是10次测试的平均次数:
使用commit()外部循环: 50条记录的8.960046267508秒
和
使用commit()外部循环: 50记录的0.3031771421432
我用约100,000条记录进行测试。
循环外使用.commit():
102150条记录15.2660858631秒
循环中使用.commit():
23.81681369933333 MINUTES 获取102150条记录
了解循环外部的.commit(),此示例还涉及102150次写入磁盘。当commit()在外面时,它会延迟写入您的数据库,直到您的所有操作都完成并缓冲。在内部,它会在每次迭代完成后立即写入数据库文件。
此外,在每个commit()之间,sqlite正在创建一个日志文件(在这种情况下,&#39; rosterdb.sqlite-journal&#39;),因此您还要创建和删除此附加文件对于每个commit(),它会增加对硬件和性能的影响。 (如果您有点好奇,可以在数据库所在的任何目录中看到此文件出现并消失。)
因此将commit()放在外面是方式,更快和在硬件上更容易。至于为什么它会返回磁盘I / O错误,我说它与这些提交的速度和频率有关()。