Re: SQLite databasefile in main memory!
by Corion (Patriarch) on Oct 06, 2005 at 09:53 UTC
|
SQLite can live in memory alone, just connect to the database :memory:. The SQLite wiki has more information on SQLite Table in Memory.
| [reply] |
|
|
Cool! But that is not using a database (file) that already exists (what I could find), but using memory from scratch! How to actually "move" the file there? How about any file?
| [reply] |
|
|
???
open file
open memory
copy from file to memory
close file
1+1=2
| [reply] |
|
|
Re: SQLite database (or any) file in main memory!
by zentara (Cardinal) on Oct 06, 2005 at 12:07 UTC
|
Maybe creating a "filesystem" in memory, and "copy" file there?That is called a ramdisk, just google for how to create one. On linux, you create it, and mount it to some mountpoint, then you can copy into it. However, you may NOT see any speed improvement, because if you have enough ram , the OS's memory management system will probably already keep the sqlite db file in memory, if it is used on a frequent basis. If you don't have enough ram, you shouldn't be using a ramdisk anyways.:-) I asked a similar question when I first started, about putting perl and it's libs in a ramdisk, to improve speed. But I found that it was like above. It takes time for the OS to load it the first time, then after that, it keeps a copy in memory automatically, unless it is forced out by some other memory hog.
I'm not really a human, but I play one on earth.
flash japh
| [reply] |
|
|
However, you may NOT see any speed improvement, because if you have enough ram , the OS's memory management system will probably already keep the sqlite db file in memory, if it is used on a frequent basis.
While this is true for many databases and other applications, it is not really true for SQLite. SQLite does an fsync() after every transaction, thus flushing out the cache, then closes and reopens the file. You therefore lose a lot of the OS's caching benefits, because changes will be written out immediately and reread. See my other post further down on how to get around that (another option IIRC is to run SQLite in non-synchronous mode, but that's only useful if you don't care much about your data :-).
| [reply] |
|
|
Yes, this crossed my mind too! But I want control! :) Aka, KNOW its there! And Im also for a solution that works in Windows too! Thus, explicitly do it in Perl! (and not rely on some 3:rd part application, creating a Ramdisk...) But I guess the OS puts it there if used regularly.. (although it would be quite fonky to do this with Perl anyway :) )
| [reply] |
|
|
Take a look at this free ram disk. I've been using it (occasionally) for a couple of years now both on NT and XP without problems.
Whether your application performance will benefit I don't know, but it very small and easy to install and it is certainly the easy option for what you are trying to do. It would take you less than 5 minutes to try it out.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
| [reply] |
Re: SQLite databasefile in main memory!
by tirwhan (Abbot) on Oct 06, 2005 at 14:14 UTC
|
As others have said, there's :memory: (though this suffers the deficiency of not allowing more than one connection and also makes persisting a pain), or you can create a virtual disk in memory (Refer to your operating system's documentation on how to do this, on Linux you could start with
mount -t tmpfs -o size=<size>m none <mountpoint>
In practice though I'd suggest you thoroughly benchmark any such solution (and benchmark it on your production system or a system which resembles it as closely as possible). You may find that you can achieve almost the same speed by intelligently designing your queries. The main speed hit SQLite takes is when it opens and closes the file at the beginning and end of a transaction. So, if you can perform all your work in a single transaction, rather than using a transaction for every query, you'll be almost as fast on a disk-based db as on a RAM-based one. For example the following quick-and-dirty benchmark:
#!/usr/bin/perl
use warnings;
use strict;
use DBI;
use Benchmark 'cmpthese';
my %db=( "on disk" => "/tmp/sqlitetest",
"in mem" => ":memory:",
"ramdisk" => "/mnt/ramfs/sqlitetest" );
my $dbh;
for my $current_db (keys %db) {
print "## Testing backing store $current_db: ##\n";
$dbh = DBI->connect("dbi:SQLite:dbname=$db{$current_db}","","")
or die "Couldn't create $current_db db";
$dbh->do(qq{create table test ( id integer, text varchar, nuthertext
+ varchar)})
or die $dbh->errstr();
for my $queries (10,100,300) {
print "$queries actions per connection:\n";
cmpthese (-5,
{ "no transact." => sub {
my $sth
= $dbh->prepare(q(insert into test values(?,?,?)));
for my $i(1..$queries) {
$sth->execute($i,'No business','like perl business');
my @row_ary
= $dbh->selectrow_array('select count(*) from test');
}
$sth->finish();
$dbh->do(qq{delete from test});
},
"transact." => sub {
$dbh->begin_work();
my $sth = $dbh->prepare(q(insert into test values(?,?,?)
+));
for my $i(1..$queries) {
$sth->execute($i,'No business','like perl business');
my @row_ary
= $dbh->selectrow_array('select count(*) from test')
+;
}
$sth->finish();
$dbh->do(qq{delete from test});
$dbh->commit();
}
}
);
}
$dbh->disconnect();
unlink $db{$current_db};
}
On my system this gives:
## Testing backing store ramdisk: ##
10 actions per connection:
Rate no transact. transact.
no transact. 372/s -- -37%
transact. 586/s 58% --
100 actions per connection:
Rate no transact. transact.
no transact. 37.1/s -- -44%
transact. 66.5/s 79% --
300 actions per connection:
Rate no transact. transact.
no transact. 11.4/s -- -44%
transact. 20.3/s 78% --
## Testing backing store in mem: ##
10 actions per connection:
Rate transact. no transact.
transact. 621/s -- -1%
no transact. 630/s 1% --
100 actions per connection:
Rate no transact. transact.
no transact. 66.1/s -- -0%
transact. 66.4/s 0% --
300 actions per connection:
Rate no transact. transact.
no transact. 20.2/s -- -0%
transact. 20.2/s 0% --
## Testing backing store on disk: ##
10 actions per connection:
Rate no transact. transact.
no transact. 42.5/s -- -84%
transact. 271/s 538% --
100 actions per connection:
Rate no transact. transact.
no transact. 4.65/s -- -92%
transact. 59.4/s 1177% --
300 actions per connection:
Rate no transact. transact.
no transact. 1.58/s -- -92%
transact. 19.6/s 1141% --
As you can see, the more actions you can cram into a single transaction, the less the performance difference between memory-based and disk-based becomes, up to the point of being negligible (I'd expect this to become even more pronounced the larger the database grows). Other caveats apply as well, e.g. if you consume too much memory your machine will go into swap. That's why it's important to benchmark.
| [reply] [d/l] [select] |
Re: SQLite database (or any) file in main memory!
by samizdat (Vicar) on Oct 06, 2005 at 13:12 UTC
|
There are many *NIX system-level routines for doing so. In BSD, 'device MD' is the system-level ramdisk. Also to be considered are shared memory (SYSVSHM). There is a slight overhead penalty for accessing chunks of this, but it's less than a filesystem access. As has already been stated, SQLite is capable of being wholly memory-resident. I'm not sure that it will stay resident, though, as the swapper comes for all of us.
The only way I know of to make sure your data will stay in memory is to compile it into the kernel, since the kernel is the only process that will never be swapped. If you carry the recompilation far enough, e.g., adding global symbols to the C compiler and Perl interpreter, you can access this as though it is just another Perl data structure. For most cases, it's rather dumb to go this far, but I have seen it done (not in Perl, in Apache w/modules) on a dedicated system, and it can provide dramatic speedups. | [reply] |
Re: SQLite database (or any) file in main memory!
by radiantmatrix (Parson) on Oct 06, 2005 at 16:21 UTC
|
There is really no way to force memory not to swap using a pure-Perl solution. This is something that is managed at the kernel level and is therefore very OS-dependent.
However, putting files in memory is possible in Perl, if you're using PerlIO (e.g. if you have perl >= 5.8.0). You can do this by:
open my $SRC, '<', $source_filename;
until (eof $SRC) {
my $buffer;
read($SRC, $buffer, 200_000);
$memfile .= $buffer;
}
close $SRC;
open my $MEM, '<', \$memfile;
## now you can read from $MEM as a filehandle
The above is example code only, there's a lot of error-handling and other considerations missing.
For a SQLite2 DB, you could attach to the database as a file, then attach to the special database :memory:, and use a couple of SQL statements to transfer the entire DB to RAM, then do all of your queries from there.
All of that said, don't be so sure you'll gain anything by doing this. Depending on what your real problem is (i.e. "why do you want this?"), you might be better off profiling your existing code and removing bottlenecks.
| [reply] [d/l] |