Как посчитать многие вещи с SQLite под Perl? - PullRequest
0 голосов
/ 20 января 2010

Я хочу сосчитать много строк (> 3G), поэтому я выбираю SQLite с таблицей (str TEXT PRIMARY KEY, count INTEGER DEFAULT 1).

Есть около 3G строк, каждая занимает 40 * 2/8 = 10 байт, таким образом, вся строка составляет 30 ГБ. Из этих 10 байтов существует 2 ^ 80 видов, что намного больше, чем 3G.

Так как эффективно обновить?

UPDATE table SET count = count + 1 WHERE str = 'xxx';
# check whether rows infected
INSERT INTO table (str) VALUES ('yyy')

Или что-то еще как INSERT OR REPLACE, с которым я не знаком.

Есть предложения?


Я иду по пути Синан Юнюр:

PRAGMA synchronous = OFF;
PRAGMA journal_mode = OFF;
PRAGMA temp_store = MEMORY;
PRAGMA auto_vacuum = NONE;
PRAGMA cache_size = 4000000;
CREATE TABLE kmers ( seq TEXT );

SELECT seq,COUNT(seq) FROM kmers GROUP BY seq;

Индекс не используется. Автокоммит 0.

И я не проверял, быстрее ли journal_mode OFF. temp_store должно быть бесполезно.

Ответы [ 2 ]

2 голосов
/ 20 января 2010

Это действительно не вопрос Perl, а вопрос SQL. В любом случае вам не нужен столбец COUNT, поскольку SQLite предоставляет встроенную функцию count для подсчета:

SELECT str, countr(str) FROM mytable GROUP BY str

должен дать вам каждый уникальный str и количество раз, которое он появляется в таблице.

Конечно, если вы определили таблицу с str в качестве первичного ключа, вы не можете вставить несколько str s по определению , поэтому ваша структура таблицы должна быть утонченный.

UPDATE:

Если бы я сделал это (и я не уверен, что сделал бы это), я бы создал таблицу с автоматически сгенерированным столбцом id и столбцом для строки. SQLite INTEGER PRIMARY KEY , 64-разрядное целое число будет достаточно для назначения уникального идентификатора каждой вставленной строке.

Тогда я бы использовал приведенный выше запрос для получения частот по строке.

Если вы вставляете через Perl DBI , обязательно выключите AutoCommit во время вставки и не забудьте зафиксировать в конце (или периодически).

Создание индекса кажется почти обязательным, но это должно быть сделано после все строки находятся в базе данных и перед выполнением любых запросов.

#!/usr/bin/perl

use strict; use warnings;

use DBI;

my $dbh = DBI->connect('dbi:SQLite:counter.db', undef, undef,
    { RaiseError => 1, AutoCommit => 0 },
);

my $sth = $dbh->prepare(q{
    INSERT INTO strings (string) VALUES(?)
});

my @strings = qw( 0123456789 9876543210 );

for ( 1 .. 10 ) {
    my $val = $strings[0.5 > rand];
    $sth->execute($val);
}

$dbh->commit;

my $result = $dbh->selectall_hashref(
    q{SELECT string, count(string) FROM strings GROUP BY string},
    'string',
);

$dbh->disconnect;

use Data::Dumper;
print Dumper $result;

SQL:

DROP TABLE strings;

CREATE TABLE strings (
    id INTEGER PRIMARY KEY,
    string char(10)
);

Выход:

$VAR1 = {
          '9876543210' => {
                            'count(string)' => '9',
                            'string' => '9876543210'
                          },
          '0123456789' => {
                            'count(string)' => '1',
                            'string' => '0123456789'
                          }
        };
0 голосов
/ 20 января 2010

INSERT OR REPLACE примерно эквивалентно выполнению DELETE для уникальных ограничений с использованием значений из строки, которая будет вставлена ​​перед выполнением INSERT.Это бесполезно для вашей цели, потому что вы не можете получить значение счетчика из старого ряда.(Значение для новой строки вычисляется до того, как он узнает, существует ли существующая строка для замены.)

Если вы ожидаете, что большинство строк будут уникальными (т.е. в большинстве случаев UPDATE будет делатьничего), тогда может быть эффективнее сначала выполнить INSERT и выдать UPDATE только в том случае, если произойдет сбой с уникальной ошибкой ограничения.

Но, как сказал Тритон, хеш будет быстрее, если выдумаю, что вы превысите свое адресное пространство.(Даже если вы превышаете доступную оперативную память, обмен может быть быстрее, чем база данных.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...