数百万条目的 SQLite 优化? [关闭]

Posted

技术标签:

【中文标题】数百万条目的 SQLite 优化? [关闭]【英文标题】:SQLite Optimization for Millions of Entries? [closed] 【发布时间】:2010-09-27 19:27:20 【问题描述】:

我正在尝试通过使用 SQLite 数据库和 Perl 模块来解决问题。最后,我需要记录数千万条记录。每个项目的唯一唯一标识符是 URL 的文本字符串。我正在考虑通过两种方式做到这一点:

方式#1:有一张好桌子,坏桌子,未排序的桌子。 (我需要检查 html 并决定是否需要它。)假设我们总共有 10 亿个页面,每个表中有 3.33 亿个 URL。我有一个要添加的新 URL,我需要检查它是否在任何表中,如果它是唯一的,则将其添加到 Unsorted。此外,我会使用此选项移动很多行。

方式 #2:我有 2 张桌子,Master 和 Good。 Master 拥有全部 10 亿个页面 URL,Good 拥有我想要的 3.33 亿个。新的URL,需要做同样的事情,除了这次我只查询一个表,我永远不会从Master中删除一行,只会将数据添加到Good。

所以基本上,我需要知道快速查询庞大的 SQLite 数据库以查看约 20 个字符的文本字符串是否唯一的最佳设置,如果不是,则添加。 p>

编辑:我现在正试图让 Berkeley DB 使用 Perl 模块工作,但没有骰子。这是我所拥有的:

use BerkeleyDB;

$dbFolder = 'C:\somedirectory';
my $env = BerkeleyDB::Env->new ( -Home => $dbFolder );

my $db  = BerkeleyDB::Hash->new (
-Filename => "fred.db", 
-Env => $env );
my $status = $db->db_put("apple", "red");

当我运行它时,我得到以下信息:

Can't call method "db_put" on an undefined value at C:\Directory\perlfile.pl line 42, <STDIN> line 1.

【问题讨论】:

我不是数据库专家(所以我可能低估了 SQLite),但您确定 SQLite 是处理这么多数据的最佳解决方案吗? 我从很多人那里听说 SQLite 非常适合处理大量数据。 ***.com/questions/3160987/… 对于大型数据集的最佳 SQLite 优化不是使用 SQLite。我从经验中知道,SQLite 会在一段时间后显着减慢插入速度。特别是如果您有不断重新计算的索引。 SQLite 的理论限制远远超出其实际限制。 我认为像 BerkeleyDB 这样的 DBM 对于这个应用程序来说会更快。使用您的字符串作为键,并使用 YAML 或 Storable 序列化所有其他数据。 实际上,我一直在努力让 BerkeleyDB 工作一段时间。我无法让它创建一个文件。我会发布我所拥有的,也许你可以帮助我。 【参考方案1】:

我倾向于使用哈希而不是 SQLite 来做你想做的事情。哈希经过优化以测试是否存在,而无需将值保持在任何排序顺序中,也无需在索引中保留数据的冗余副本。应用于数据的散列算法产生它的存储位置,如果它确实存在的话;你可以寻找那个位置,看看它是否在那里。我认为您不需要将哈希表保存在 RAM 中。

以下是您可以采用混合哈希/SQLite 方法的方法。

创建一个 SQLite 表

STORE
id INTEGER PRIMARY KEY
BUCKET (integer, indexed) 
URL (text, not indexed)
status 

如果您想按状态将它们分开,您可以拥有其中三个表,STORE1、STORE2 和 STORE3。

假设每个商店中将有 250,000,001 个不同的存储桶。 (您可以试验这个数字;将其设为质数)。

找到一个哈希算法,它接受两个输入,即 URL 字符串和 250,000,0001,并返回一个介于 1 和 250,000,001 之间的数字。

当您获得一个 URL 时,将其提供给哈希算法,它会告诉您要查看哪个 BUCKET:

Select * from STORE where BUCKET = 您的哈希函数返回的值。

您在 BUCKET 字段上的索引将快速返回行,并且您可以检查 URL。如果当前 URL 不是其中之一,添加它:

INSERT STORE(BUCKET, URL) VALUES( your hash return value, theURL). 

SQLite 将索引整数值,我认为这将比索引 URL 更有效。并且 URL 将只存储一次。

【讨论】:

Err,索引整数值可能更有效,但这只是因为按字符串索引可能相当于您的存储桶计算,只是效率更高。这是一般性观察,可能不适用于 SQLite,但我敢打赌。 请详细说明一下,为什么 SQLite 用于插入 btree 的 URL 比计算存储桶的哈希算法更有效?其次,您的批评没有解决我建议的方法可以避免的 URL 值的重复。我坚持我最初的建议:hash 比 btree 更好,因为 hash 不会随着插入而降级——没有 btree 可以保持平衡。这种混合方法不会像纯哈希方法那样有效。我只是建议它可能比索引 URL 列更好,假设 OP 必须使用像 SQLite 这样的关系数据库。 在第一点上,我不是在争论——我在问为什么计算 URL 的哈希桶的效率低于二进制算法来决定将 URL 放在哪里当有 10 亿个 URL(或 3.33 亿个 URL,如果集合被分成单独的表)时的 btree。我的假设是,在某些时候,hash-calc 的效率会超过二进制 calc,因为 hash-calc 不会涉及磁盘读取。 我不知道它是否更有效,但我猜测您正在用一个 btree 换取索引 url 以获得客户端的额外工作,再加上两个 btree (一个用于主键,一个用于存储桶索引)在 sqlite 中,并且看不到这可能是一个改进。似乎您期望 sqlite 对整数索引做一些显着不同的事情?我不是那么假设。 重新避免重复 URL 值,我不确定您的意思。我假设 url 是主键,所以显然没有重复。【参考方案2】:

如果$db 未定义,则打开数据库失败,您应该检查$!$BerkeleyDB::Error 以了解原因。

您是否已经创建了数据库?如果没有,你需要-Flags =&gt; DB_CREATE

工作示例:

use strict;
use warnings;
use BerkeleyDB;

my $dbFolder = '/home/ysth/bdbtmp/';

my $db  = BerkeleyDB::Hash->new (
    -Filename => "$dbFolder/fred.db", 
    -Flags => DB_CREATE,
) or die "couldn't create: $!, $BerkeleyDB::Error.\n";

my $status = $db->db_put("apple", "red");

不过,我无法让 BerkeleyDB::Env 做任何有用的事情;无论我尝试了什么,构造函数都返回了 undef。

【讨论】:

我添加了 DB_CREATE 并检查了 $!创建环境后,它只说“没有这样的文件或目录”。你介意给我一个工作样本让我解剖吗?我需要做的就是在磁盘上创建一个哈希,向其中添加项目,然后检查现有项目。 @Sho Minamimoto:添加了一个例子 搞定了。我认为问题在于我放了“fred.db”而不是完整路径,但是在文档中它说无论Env在哪里都应该创建数据库。那好吧。感谢您的帮助! 最后一件事,有数百万个条目,我将如何按值排序?就像我有一些值为“0”的关键 URL 和一些值为“1”的关键 URL,我将如何只获取值为“0”的 URL?这会很快吗? @Sho Minamimoto:不,必须通过坏的肯定会减慢获得好的。如果您需要尽可能快,最好使用好的、坏的和未排序的文件(或者可能是好的、全部和未排序的?不确定您想如何使用它。)【参考方案3】:

我不知道这是否最佳,但您可以设置您的 SQLite 数据库,使“好”表对 URL 列具有唯一约束。您可能没有足够的 RAM 来在 Perl 中进行比较(天真的解决方案是创建一个以 URL 为键的哈希,但如果您有十亿页,您将需要大量内存)。

当需要插入时,数据库将强制唯一性,并在尝试插入重复的 URL 时抛出某种错误。只要 DBI 针对不同的错误消息返回不同的错误值,您就可以捕获并忽略它。

【讨论】:

以上是关于数百万条目的 SQLite 优化? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

删除数百万条记录 oracle [关闭]

mysql如何更快地插入数百万条记录? [关闭]

Sqlite3写性能优化-每秒百万条写入

多连接数百万条记录的优化查询需要建议

每天存储数百万条可分组用于统计目的的数据的最佳方式是啥?

优化插入数百万条记录,MySQL 和 PHP