执行和追踪

执行模式

仅当您一次给出多条SQL语句时,此部分才有意义 Cursor.execute 。(语句之间用分号分隔。)

SQLite分两步执行。首先准备一条语句,它验证语法、表和字段,并将语句转换为内部表示形式。然后运行准备好的语句。当行可用、出现错误或语句完成时,执行停止。

这个 Cursor.execute() 方法自动执行准备并开始执行。如果所有语句都没有返回行,则执行将转到末尾。如果返回一行,则使用游标作为迭代器。将根据需要恢复执行以返回每个结果行。

然而,这意味着如果您不读取返回的行,则您的其余语句将不会执行。APSW将检测以前未执行的语句并生成异常。例如::

>>> cursor.execute("select * from foo ; create table bar(x,y,z)")
>>> cursor.execute("create table bam(x,y,z)")
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
apsw.IncompleteExecutionError: Error: there are still remaining sql statements to execute

因为我没有读到结果 select * from foo 那么下面的CREATE TABLE命令就没有机会被执行了。在下一次执行时,会检测到该条件并引发异常。

多线程和可重入性

ASPW允许您在多线程程序中使用SQLite,并将在SQLite工作时让其他线程执行。它在启动时检查SQLite是否已编译为 threadsafe mode 这是默认设置。这个 GIL 在调用SQLite API时释放,并在运行任何Python代码时重新获取。

不能在多个线程中同时使用同一游标对象来执行语句。APSW将检测到这一点并引发 ThreadingViolationError 。连续使用对象是安全的(例如,调用 Cursor.execute() 在一个线程中使用,在另一个线程中使用迭代器。你也不能做像试着 close() 在两个线程中并发的连接。

如果您有多个线程和/或多个程序访问同一数据库,则可能会争用该文件。SQLite将返回SQLITE_BUSY,它将被引发为BusyError。你可以打电话给 Connection.setbusytimeout() 要设置SQLite重试的时间,请执行以下操作 Connection.setbusyhandler() 来安装您自己的忙碌处理程序。请注意,如果SQLite认为已出现死锁,则它不会调用繁忙处理程序或超时。描述了SQLite的锁定和并发 here

游标对象一次只能执行一个查询。不能从跟踪函数内部、用户定义的函数或归类发出新查询,因为在执行查询时会调用这些函数或归类。但是,您可以创建新的游标并使用这些游标而不会出现问题。在设置跟踪或用户定义的函数时,您可能希望记住连接对象。

64位主机

APSW经过测试,可在32位和64位主机上正常工作。SQLite对于字符串、BLOB、列数等限制为32位数量,即使在编译为64位时也是如此。你会得到一个 TooBigError 如果尝试使用大于1 GB的字符串和Blob。

语句高速缓存

每个 Connection 维护将SQL查询映射到 prepared statement 避免……的开销 repreparing 多次执行的查询。这是使用更多内存来减少CPU消耗的典型权衡。

默认情况下,缓存中最多有100个条目。缓存已满后,最近最少使用的项将被丢弃,以便为新项腾出空间。

如果您运行的唯一查询超过100个,则应该选择更大的高速缓存大小。例如,如果您有101个不同的查询按顺序运行,那么缓存将无济于事。

如果您正在使用 authorizers 请注意,只有在准备语句时才会调用授权程序回调。你可以的 specify zero 这将完全禁用语句缓存,请使用 can_cache = False 标志为 execute /Executeman

追踪

您可以在上安装跟踪器 cursorsconnections 作为一种简单的方式,可以准确查看执行了什么以及返回了什么。跟踪程序还可以中止执行并导致返回不同的值。这对于诊断和测试非常有用,而不必修改主代码。

备注

不能对从中调用跟踪程序的游标发出新的EXECUTE语句。如果您希望在跟踪程序中进行更多查询,则可以从新的游标对象进行查询。例如::

def exectracer(cursor, sql, bindings):
  cursor.connection.cursor().execute("insert into log values(?,?)", (sql,str(bindings)))
  return True

执行跟踪器

执行跟踪程序是在准备好SQL语句之后调用的。(例如,语法错误将在准备过程中导致异常,因此您不会在跟踪程序中看到它们)。它由三个参数调用。

游标

执行语句的游标

SQL

正在执行的SQL文本

绑定

正在使用的绑定。这可能是 `None 、词典或元组。

如果跟踪程序返回值为FALSE,则中止执行,并返回 ExecTraceAbort 例外。请参阅 example

可以通过设置在特定游标上安装执行跟踪器 Cursor.exectrace 或通过设置所有游标的 Connection.exectrace ,以光标跟踪器为优先。

如果您使用连接 with 语句并具有连接执行跟踪程序,则在APSW创建和释放/回滚保存点时也将调用您的回调。第一个参数不是游标,而是连接本身,因为不涉及游标。

行跟踪器

在返回每一行之前调用行跟踪器。它使用两个参数进行调用。

游标

返回该行的游标

即将返回的值的元组

从跟踪程序返回的内容实际上是返回给 execute() 。如果返回NONE,则跳过整行。请参阅 example

可以通过设置在特定游标上安装行跟踪器 Cursor.rowtrace 或通过设置所有游标的 Connection.rowtrace ,以光标跟踪器为优先。

APSW跟踪

APSW包括一个跟踪程序,使您可以轻松跟踪SQL执行情况,并在不修改代码的情况下提供摘要报告。

$python3-m apsw.trace [apswtrace options] yourscript.py [your options]

所有输出均为UTF-8编码。以下选项可用:

$ python3 -m apsw.trace --help
Usage: apswtrace.py [options] pythonscript.py [pythonscriptoptions]

This script runs a Python program that uses APSW and reports on SQL queries
without modifying the program.  This is done by using connection_hooks and
registering row and execution tracers.  See APSW documentation for more
details on the output.

Options:
  -h, --help            show this help message and exit
  -o OUTPUT, --output=OUTPUT
                        Where to send the output.  Use a filename, a single
                        dash for stdout, or the words stdout and stderr.
                        [stdout]
  -s, --sql             Log SQL statements as they are executed. [False]
  -r, --rows            Log returned rows as they are returned (turns on sql).
                        [False]
  -t, --timestamps      Include timestamps in logging
  -i, --thread          Include thread id in logging
  -l LENGTH, --length=LENGTH
                        Max amount of a string to print [30]
  --no-report           A summary report is normally generated at program
                        exit.  This turns off the report and saves memory.
  --report-items=N      How many items to report in top lists [15]
  --reports=REPORTS     Which reports to show
                        [summary,popular,aggregate,individual]

这是带有以下选项的示例输出: --sql--rows--timestamps--thread

1e0e5a0 0.152 7fccea8456e0 OPEN: ":memory:" unix READWRITE|CREATE
1f72ac0 0.161 7fccea8456e0 OPEN: "testdb" unix READWRITE|CREATE
1f6b8d0 0.162 7fccea8456e0 CURSORFROM: 1f72ac0 DB: "testdb"
1f6b8d0 0.162 7fccea8456e0 SQL: create table foo(x,y,z)
1f6b8d0 0.239 7fccea8456e0 CURSORFROM: 1f72ac0 DB: "testdb"
1f6b8d0 0.239 7fccea8456e0 SQL: insert into foo values(?,?,?) BINDINGS: ("kjfhgk", "gkjlfdhgjkhsdfkjg", "gklsdfjgkldfjhnbnvc,mnxb,mnxcv..")
1f6b8d0 0.242 7fccea8456e0 CURSORFROM: 1f72ac0 DB: "testdb"
1f6b8d0 0.242 7fccea8456e0 SQL: insert into foo values(?,?,?) BINDINGS: ("gdfklhj", ":gjkhgfdsgfd", "gjkfhgjkhdfkjh")
1f6b8d0 0.244 7fccea8456e0 CURSORFROM: 1f72ac0 DB: "testdb"
1f6b8d0 0.245 7fccea8456e0 SQL: insert into foo values(?,?,?) BINDINGS: ("gdfjkhg", "gkjlfd", "")
1f6b8d0 0.247 7fccea8456e0 CURSORFROM: 1f72ac0 DB: "testdb"
1f6b8d0 0.247 7fccea8456e0 SQL: insert into foo values(?,?,?) BINDINGS: (1, 2, 30)
1f6b8d0 0.257 7fccea8456e0 CURSORFROM: 1f72ac0 DB: "testdb"
1f6b8d0 0.257 7fccea8456e0 SQL: select longest(x,y,z) from foo
1f6b8d0 0.257 7fccea8456e0 ROW: ("gklsdfjgkldfjhnbnvc,mnxb,mnxcv..")

每一行都以以下字段开头:

ID

这是 idCursorConnection 。你可以很容易地 filter 如果您只想找出在特定游标或连接上发生的情况,则可以使用日志。

时间戳

这是程序启动以来的时间(以秒为单位

苏拉迪德

独一无二的 thread identifier

行的其余部分具有以下形式之一:

OPEN:“数据库名”VFS OPEN_FLAGS

A Connection 已经打开了。这个 dbname 文件名是否与调用 Connectionvfs 是对象的名称 VFS 用于打开数据库。 open_flags 是一组 flags 随主板一起提供 SQLITE_OPEN 省略了前缀。

CURSORFROM:Connectionid数据库:“数据库名”

已分配游标。这个 id 在该行的开头是新游标的。 connectionid 是从中创建它的连接的ID。这个 dbname 为方便起见而提供。游标第一次发出查询时会记录此消息。

SQL:查询绑定:绑定

已对游标发出查询。

行:行

游标返回了结果行。

默认情况下,还会生成报告。这是运行测试套件的示例输出。在计算查询的时间时,您的代码执行时间也包括在内。例如,如果您的查询返回10行,并且您在读取每一行时休眠了1秒,那么查询的时间将被记录为10秒。因为您可以同时有多个活动的查询,也可以跨多个线程,所以总的处理时间可能大于程序运行时间。仅记录没有结果的查询或读取所有结果行的查询的处理时间。处理时间还包括繁忙连接上的等待时间。

APSW TRACE SUMMARY REPORT

Program run time                    83.073 seconds
Total connections                   1308
Total cursors                       3082
Number of threads used for queries  21
Total queries                       127973
Number of distinct queries          578
Number of rows returned             2369
Time spent processing queries       120.530 seconds

这显示了每个查询运行的次数。

MOST POPULAR QUERIES

 121451 insert into foo values(?)
   1220 insert into abc values(1,2,?)
   1118 select x from foo
    909 select timesten(x) from foo where x=? order by x
    654 select * from foo
    426 update t1 set b=b||a||b
    146 begin
     88 create table foo(x,y)
     79 insert into foo values(1,2)
     76 rollback
     71 pragma locking_mode=exclusive
     71 insert into t1 values(2, 'abcdefghijklmnopqrstuvwxyz')
     71 insert into t1 values(1, 'abcdefghijklmnopqrstuvwxyz')
     71 insert into t1 select 4-a, b from t2
     71 insert into foo values(date('now'), date('now'))

它显示了运行查询的次数和处理时间的总和(以秒为单位)。这个 begin immediate 查询说明了如何将忙碌等待时间包括在内。

LONGEST RUNNING - AGGREGATE

    413   94.305 select timesten(x) from foo where x=? order by x
 120637   12.941 select * from foo
     12    4.115 begin immediate
 121449    2.179 insert into foo values(?)
   1220    1.509 insert into abc values(1,2,?)
      3    1.380 create index foo_x on foo(x)
    426    0.715 update t1 set b=b||a||b
     38    0.420 insert into foo values(?,?)
     71    0.241 create table t1(a unique, b)
     88    0.206 create table foo(x,y)
     61    0.170 create table abc(a,b,c)
     27    0.165 insert into foo values(?,?,?)
      1    0.158 select row,x,snap(x) from foo
     80    0.150 insert into foo values(1,2)
     71    0.127 insert into foo values(date('now'), date('now'))

这显示了运行时间最长的查询,以秒为单位。

LONGEST RUNNING - INDIVIDUAL

  3.001 begin immediate
  1.377 create index foo_x on foo(x)
  1.102 begin immediate
  0.944 select timesten(x) from foo where x=? order by x
  0.893 select timesten(x) from foo where x=? order by x
  0.817 select timesten(x) from foo where x=? order by x
  0.816 select timesten(x) from foo where x=? order by x
  0.786 select timesten(x) from foo where x=? order by x
  0.783 select timesten(x) from foo where x=? order by x
  0.713 select timesten(x) from foo where x=? order by x
  0.701 select timesten(x) from foo where x=? order by x
  0.651 select timesten(x) from foo where x=? order by x
  0.646 select timesten(x) from foo where x=? order by x
  0.631 select timesten(x) from foo where x=? order by x
  0.620 select timesten(x) from foo where x=? order by x