11. A bit more faster.
$dbh->begin_work;
for (@data) {
$sth->execute($_);
}
$dbh->commit;
12. A bit more faster (maybe).
my $ct = 0;
$dbh->begin_work;
for (@data) {
$sth->execute($_);
# this number is arbitrary
unless (++$ct % 1000) {
$dbh->commit;
$dbh->begin_work;
}
}
$dbh->commit;
14. Much faster
(but dangerous; SQLite only)
$dbh->do("PRAGMA synchronous = OFF");
for (@data) {
...
}
$dbh->do("PRAGMA synchronous = FULL");
15. Much faster (since 1.37)
# INSERT INTO foo VALUES (?),(?),...
my $placeholders = join ",", ('(?)') x 500;
my $stmt = "INSERT INTO foo VALUES $placeholders";
my $sth = $dbh->prepare($stmt);
while (@data) {
if (@data > 500) {
$sth->execute(splice @data, 0, 500);
} else {
...
}
}
16. Summary
Use "prepare".
Don't insert one by one.
Don't insert everything at once.
Do The Right Thing when ACIDity matters.
Multi-row insert may help.
Beware SQLITE_MAX_VARIABLE_NUMBER
(default: 999)
18. An in-memory database
is quite fast.
# volatile, in-memory database
my $dbh = DBI->connect('dbi:SQLite::memory:'...);
# cf. volatile database based on a temporary file
# my $dbh = DBI->connect('dbi:SQLite:'...);
19. It's also handy
for tests.
{
my $dbh = DBI->connect('dbi:SQLite::memory:'...);
... # do whatever you need
}
# everything is gone
(Cleaning-up files may be a bit tricky)
21. Back it up as
necessary.
if (!Test::More->builder->is_passing) {
$dbh->sqlite_backup_to_file("failed.db");
}
22. Load into an in-
memory database.
my $dbh = DBI->connect('dbi:SQLite::memory:‘...);
$dbh->sqlite_backup_from_file("backup.db");
23. CAVEATS
Loading time may matter.
Everything is REPLACED (naturally).
Just copying a file may suffice.
Shared (read) lock helps.
http://www.sqlite.org/backup.html
36. CAVEATS
ATTACH before you begin a transaction.
Beware SQLITE_MAX_ATTACHED
(default: 10)
Split a database if concurrency really
matters.
Or use better server/client databases.
38. May be a problem.
my $select =
"SELECT id FROM foo WHERE status = 0 LIMIT 1";
my $update = "UPDATE foo SET status = 1 WHERE id = ?";
my ($id) = $dbh->selectrow_array($select);
$dbh->do($update, undef, $id);
39. Update first to
get a write lock.
my $update = q{
UPDATE foo SET status = 1
WHERE id = (
SELECT id FROM foo
WHERE status = 0 LIMIT 1
)
};
40. What should we do
to find an updated
row?
# $dbh->last_insert_id doesn't work
41. "update_hook" may help.
my ($action, $database, $table, $rowid);
$dbh->sqlite_update_hook(sub {
($action, $database, $table, $rowid) = @_;
...
# you can't do anything that modifies
# the database connection (incl. "prepare")
});
$dbh->do($update);
42. Retreive the row
with the id.
my $stmt = "SELECT * FROM foo WHERE ROWID = ?";
my $row = $dbh->selectrow_arrayref(
$stmt, undef, $rowid
);
43. NOTE
Also sqlite_(commit|rollback)_hook
One hook per connection
Optional "UPDATE ... LIMIT" clause?
SQLITE_ENABLE_UPDATE_DELETE_LIMIT
Amalgamated source doesn't support this
(because part of the source needs to be
regenerated).
55. SQLite Pragmata to
get information
PRAGMA database_list
PRAGMA table_info('table')
PRAGMA foreign_key_list('table')
56. To get info of
attached databases.
PRAGMA db.table_info('table')
PRAGMA db.foreign_key_list('table')
57. System tables
SELECT * FROM sqlite_master;
SELECT * FROM sqlite_temp_master;
# SQLs stored in system tables are not
always what you used to create tables
64. Check "SCAN TABLE"
without using indices.
my $stmt = "SELECT * FROM foo WHERE id = ?";
my $sth = $dbh->prepare("EXPLAIN QUERY PLAN $stmt");
$sth->execute(1);
while(my $plan = $sth->fetchrow_hashref) {
my $detail = $plan->{detail};
if ($detail =~ /SCAN TABLE/ && $detail !~ /INDEX/)
{
...
}
}
65. In case you want to know
memory usage etc...
my $status = DBD::SQLite::sqlite_status();
my $status = $dbh->sqlite_db_status();
my $status = $sth->sqlite_st_status();
77. How to write an extension
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1;
int sqlite3_extension_init(
sqlite3 *db,
char **error,
const sqlite3_api_routines *api
){
SQLITE_EXTENSION_INIT2(api);
/* do whatever you like */
return SQLITE_OK;
}
78. Use XS for more portability.
#include <EXTERN.h>
#include <perl.h>
#include <XSUB.h>
#include "sqlite3ext.h“
SQLITE_EXTENSION_INIT1;
int sqlite3_extension_init(...) {
SQLITE_EXTENSION_INIT2(api);
...
}
MODULE = DBD::SQLite::Extension PACKAGE
= DBD::SQLite::Extension
PROTOTYPES: DISABLE
79. Prepare Makefile.PL
use strict;
use warnings;
use ExtUtils::MakeMaker;
# Get installed header files
get_sqlite_header("sqlite3.h") or exit;
get_sqlite_header("sqlite3ext.h") or exit;
WriteMakefile(
NAME => 'DBD::SQLite::Extension',
CONFIGURE_REQUIRES => {
'File::ShareDir' => '1.0', # to get headers
'DBD::SQLite' => '1.38_01',
},
FUNCLIST => ['sqlite3_extension_init'],
DL_FUNCS => {'DBD::SQLite::Extension' => []},
);
80. It Works.
my $dll =
"./blib/arch/auto/DBD/SQLite/Extension/Extension.dll";
my $dbh = DBI->connect('dbi:SQLite::memory:');
$dbh->sqlite_enable_load_extension(1);
$dbh->sqlite_load_extension($dll);
81. NOTE
Needs more tricks to make complex
extensions (malloc/free conflicts,
DBI macros etc)
Use always the same headers as used
in DBD::SQLite
"Using SQLite" (O’Reilly) helps.
85. Deferred Transaction
SQLite default
Maximum concurrency
May cause a deadlock (multiple
clients in transactions wait for
others releasing their locks)
86. Immediate Transaction
DBD::SQLite’s current default
Immediately reserve a write lock
No deadlock (if you can begin a
transaction, you'll most probably be
able to commit either).
87. Why changed?
by request (#56444, in April 2010)
(other reports on locking issues:
#42205, #46289 (both in 2009))
to avoid unexpected errors/deadlocks
while testing.
ditto for smaller web applications.
After all, who uses DBD::SQLite most?
101. $dbh->type_info(_all) is not
implemented yet.
$sth->{TYPE} returns an array
ref of strings. (Not conformed
to the DBI spec.)
Dynamic typing / Type affinity