让 Python 更加充分的使用 Sqlite3
我最近在涉及大量数据处理的项目中频繁使用 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生成器是非常方便的,可以让你将数据生成与数据消耗分离。
4. 使用Context Managers(上下文管理器)
即使在处理SQL事务的中间,也会发生讨厌的事情。为了避免手动处理回滚或提交,你可以简单地使用连接对象作为上下文管理器。 在以下示例中,我们创建了一个表,并错误地插入了重复的值:
import sqlite3
connection = sqlite3.connect(':memory:')
with connection:
connection.execute(
'CREATE TABLE events(ts, msg, PRIMARY KEY(ts, msg))')
try:
with connection:
connection.executemany('INSERT INTO events VALUES (?, ?)', [
(1, 'foo'),
(2, 'bar'),
(3, 'baz'),
(1, 'foo'),
])
except (sqlite3.OperationalError, sqlite3.IntegrityError) as e:
print('Could not complete operation:', e)
# No row was inserted because transaction failed
for row in connection.execute('SELECT * FROM events'):
print(row)
connection.close()
5. 使用Pragmas
…当它真的有用时
在你的程序中有几个 pragma 可用于调整 sqlite3 的行为。特别地,其中一个可以改善性能的是synchronous:
connection.execute('PRAGMA synchronous = OFF')
你应该知道这可能是危险的。如果应用程序在事务中间意外崩溃,数据库可能会处于不一致的状态。所以请小心使用! 但是如果你要更快地插入很多行,那么这可能是一个选择。
6. 推迟索引创建
假设你需要在数据库上创建几个索引,而你需要在插入很多行的同时创建索引。把索引的创建推迟到所有行的插入之后可以导致实质性的性能改善。
7. 使用占位符插入 Python 值
使用 Python 字符串操作将值包含到查询中是很方便的。但是这样做非常不安全,而 sqlite3 给你提供了更好的方法来做到这一点:
# Do not do this!
my_timestamp = 1
c.execute("SELECT * FROM events WHERE ts = '%s'" % my_timestamp)
# Do this instead
my_timestamp = (1,)
c.execute('SELECT * FROM events WHERE ts = ?', my_timestamp)
此外,使用Python%s(或格式或格式的字符串常量)的字符串插值对于executemany来说并不是总是可行。所以在此尝试没有什么真正意义!
请记住,这些小技巧可能会(也可能不会)给你带来好处,具体取决于特定的用例。你应该永远自己去尝试,决定是否值得这么做。
让 Python 更加充分的使用 Sqlite3的更多相关文章
- Python标准库14 数据库 (sqlite3)
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Python自带一个轻量级的关系型数据库SQLite.这一数据库使用SQL语言.S ...
- Python 3.6.0的sqlite3模块无法执行VACUUM语句
Python 3.6.0的sqlite3模块存在一个bug(见issue 29003),无法执行VACUUM语句. 一执行就出现异常: Traceback (most recent call last ...
- 利用python将数据转存入sqlite3
案例的目标是将存在文件中的json格式数据转存到sqlite数据库中.因此,需要利用python逐行读取json文件中数据,对数据进行解析和入库.具体操作步骤如下: 1.逐行读取json文件 for ...
- 吴裕雄--python学习笔记:通过sqlite3 进行文字界面学生管理
import sqlite3 conn = sqlite3.connect('E:\\student.db') print("Opened database successfully&quo ...
- Python 中 sqlite3的使用
Python 中 sqlite3的使用 一.sqlite安装 下载地址 http://www.sqlite.org 1.数据库生成 sqlite3.exe testdb 2.创建表格,插入数据 3.在 ...
- SQLite3基本使用从shell到python
SQLite是一个轻量级的关系型数据库,在訪问量不超过10万PV的中小站点中使用绰绰有余. 并且使用方便,接口简单,以下从命令行和python接口双方面介绍SQLite3的基本操作. 在linux终端 ...
- Python学习笔记21:数据库操作(sqlite3)
Python自带一个轻量级的关系型数据库SQLite.这一数据库使用SQL语言. SQLite作为后端数据库,能够搭配Python建站点,或者制作有数据存储需求的工具. SQLite还在其他领域有广泛 ...
- python加载sqlite3报错:No module named _sqlite3
环境为Ubuntu16.04 Apache2.4 Python2.7.13 django 1.8 今天部署apache+django,经过各种折腾,好不容易配置完了,发现错误Apache的日志里有一项 ...
- python 对 sqlite3的简单使用
SQLite是一种嵌入式数据库,它的数据库就是一个文件.由于SQLite本身是C写的,而且体积很小,所以,经常被集成到各种应用程序中,甚至在iOS和Android的App中都可以集成.Python就内 ...
随机推荐
- 小丸工具箱FAQ
下载地址:https://maruko.appinn.me/index.html 本文章是把一些使用小丸工具箱中常见的操作失误或出错的问题集中写出并提出解决方法,以便大家寻找解决并避免重复提问. 文章 ...
- POJ2115 C Looooops 扩展欧几里德
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ2115 题意 对于C的for(i=A ; i!=B ;i +=C)循环语句,问在k位存储系统中循环几次 ...
- BZOJ1030 [JSOI2007]文本生成器 AC自动机 动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1030 题意概括 给出n个模式串,问长度为m的串中有多少个至少含有这n个模式串中的任意一个. 注意, ...
- 使用numpy产生随机数
numpy中的random模块包含了很多方法可以用来产生随机数,这篇文章将对random中的一些常用方法做一个总结. 1.numpy.random.rand(d0, d1, ..., dn) 作用:产 ...
- 基于python的机器学习开发环境安装(最简单的初步开发环境)
一.安装Python 1.下载安装python3.6 https://www.python.org/getit/ 2.配置环境变量(2个) 略...... 二.安装Python算法库 安装顺序:Num ...
- mac 回车键、空格键失灵(非物理原因)解决方法
1.关机2.按住shift+control+option+开关机键,大概10秒左右,观察键盘电源灯是否变色,确定是否硬件故障,不变色表正常.3.先按下开关机键后,放开.然后同时按住option+com ...
- C++雾中风景番外篇3:GDB与Valgrind ,调试代码内存的工具
写 C++的同学想必有太多和内存打交道的血泪经验了,常常被 C++的内存问题搅的焦头烂额.(写 core 的经验了)有很多同学一见到 core 就两眼一抹黑,不知所措了.笔者 入"坑&quo ...
- Flutter常用组件(Widget)解析-Text
单一格式的文本. 文本组件是以字符串形式显示的单一格式,这个文本字符串可以是多行显示也可以是单独一行显示,主要取决于你的布局限制. 这样式内容是可选择的,如果你省略了,则会使用文本的默认样式来显示.如 ...
- 创建PCB原理图的模板
Q:创建PCB原理图的模板,主要就是设置模板的大小,右下角的信息框, 效果图如下: 创建PCB工程 创建原理图 设置模板,方便以后画原理图 打开模板的方式有:1按DO 2双击边框 标题块是附带有的,取 ...
- Android避免快速双击按钮最简单好用的方式
代码如下,直接放到工具类中即可.类可以实现Onclicklistener,然后重写onClick方法,直接将该函数写在onClick方法中即可,这样对于所有的点击事件都将生效. 避免了快速双击出现的异 ...