本文整理自网络,侵删。
我最近在涉及大量数据处理的项目中频繁使用 sqlite3。我最初的尝试根本不涉及任何数据库,所有的数据都将保存在内存中,包括字典查找、迭代和条件等查询。这很好,但可以放入内存的只有那么多,并且将数据从磁盘重新生成或加载到内存是一个繁琐又耗时的过程。
我决定试一试sqlite3。因为只需打开与数据库的连接,这样可以增加可处理的数据量,并将应用程序的加载时间减少到零。此外,我可以通过 SQL 查询替换很多Python逻辑语句。
我想分享一些关于这次经历的心得和发现。
TL;DR
- 使用大量操作 (又名 executemany)。
- 你不需要使用光标 (大部分时间)。
- 光标可被迭代。
- 使用上下文管理器。
- 使用编译指示 (当它有意义)。
- 推迟索引创建。
- 使用占位符来插入 python 值。
1. 使用大量操作
如果你需要在数据库中一次性插入很多行,那么你真不应该使用 execute。sqlite3 模块提供了批量插入的方式:executemany。
而不是像这样做:
for row in iter_data(): connection.execute('INSERT INTO my_table VALUES (?)', row)
你可以利用这个事实,即 executemany 接受元组的生成器作为参数:
connection.executemany( 'INSERT INTO my_table VALUE (?)', iter_data() )
这不仅更简洁,而且更高效。实际上,sqlite3 在幕后利用 executemany 实现 execute,但后者插入一行而不是多行。
我写了一个小的基准测试,将一百万行插入空表(数据库在内存中):
executemany: 1.6 秒
execute: 2.7 秒
2. 你不需要游标
一开始我经常搞混的事情就是,光标管理。在线示例和文档中通常如下:
connection = sqlite3.connect(':memory:') cursor = connection.cursor() # Do something with cursor
但大多数情况下,你根本不需要光标,你可以直接使用连接对象(本文末尾会提到)。像execute和executemany类似的操作可以直接在连接上调用。以下是一个证明此事的示例:
import sqlite3 connection = sqlite3(':memory:') # Create a table connection.execute('CREATE TABLE events(ts, msg)') # Insert values connection.executemany( 'INSERT INTO events VALUES (?,?)', [ (1, 'foo'), (2, 'bar'), (3, 'baz') ] ) # Print inserted rows for row in connnection.execute('SELECT * FROM events'): print(row)
3. 光标(Cursor)可被用于迭代
你可能经常会看到使用fetchone或fetchall来处理SELECT查询结果的示例。但是我发现处理这些结果的最自然的方式是直接在光标上迭代:
for row in connection.execute('SELECT * FROM events'): print(row)
这样一来,只要你得到足够的结果,你就可以终止查询,并且不会引起资源浪费。当然,如果事先知道你需要多少结果,可以改用LIMIT SQL语句,但Python生成器是非常方便的,可以让你将数据生成与数据消耗分离。
相关阅读 >>
python的flask框架中使用flask-sqlalchemy管理数据库的教程
Sqlite之c#版 system.data.Sqlite使用方法
更多相关阅读请进入《Sqlite》频道 >>

数据库系统概念 第6版
本书主要讲述了数据模型、基于对象的数据库和XML、数据存储和查询、事务管理、体系结构等方面的内容。