Jon*_*Jon 18 .net c# sqlite system.data.sqlite
我正在使用C#导入一个包含6-8百万行的CSV.
我的表看起来像这样:
CREATE TABLE [Data] ([ID] VARCHAR(100) NULL,[Raw] VARCHAR(200) NULL)
CREATE INDEX IDLookup ON Data(ID ASC)
Run Code Online (Sandbox Code Playgroud)
我正在使用System.Data.SQLite来进行导入.
目前在Windows 7 32位,Core2Duo 2.8Ghz和4GB RAM上耗时6分55秒.这不是太糟糕,但我只是想知道是否有人能够更快地看到导入它的方法.
这是我的代码:
public class Data
{
public string IDData { get; set; }
public string RawData { get; set; }
}
string connectionString = @"Data Source=" + Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory + "\\dbimport");
System.Data.SQLite.SQLiteConnection conn = new System.Data.SQLite.SQLiteConnection(connectionString);
conn.Open();
//Dropping and recreating the table seems to be the quickest way to get old data removed
System.Data.SQLite.SQLiteCommand command = new System.Data.SQLite.SQLiteCommand(conn);
command.CommandText = "DROP TABLE Data";
command.ExecuteNonQuery();
command.CommandText = @"CREATE TABLE [Data] ([ID] VARCHAR(100) NULL,[Raw] VARCHAR(200) NULL)";
command.ExecuteNonQuery();
command.CommandText = "CREATE INDEX IDLookup ON Data(ID ASC)";
command.ExecuteNonQuery();
string insertText = "INSERT INTO Data (ID,RAW) VALUES(@P0,@P1)";
SQLiteTransaction trans = conn.BeginTransaction();
command.Transaction = trans;
command.CommandText = insertText;
Stopwatch sw = new Stopwatch();
sw.Start();
using (CsvReader csv = new CsvReader(new StreamReader(@"C:\Data.txt"), false))
{
var f = csv.Select(x => new Data() { IDData = x[27], RawData = String.Join(",", x.Take(24)) });
foreach (var item in f)
{
command.Parameters.AddWithValue("@P0", item.IDData);
command.Parameters.AddWithValue("@P1", item.RawData);
command.ExecuteNonQuery();
}
}
trans.Commit();
sw.Stop();
Debug.WriteLine(sw.Elapsed.Minutes + "Min(s) " + sw.Elapsed.Seconds + "Sec(s)");
conn.Close();
Run Code Online (Sandbox Code Playgroud)
Cza*_*zak 12
600万条记录的速度非常快.
看来你正在以正确的方式做到这一点,前段时间我在sqlite.org上看到,在插入记录时你需要将这些插入放在事务中,如果不这样做,你的插入将仅限于60每秒!这是因为每个插入都将被视为一个单独的事务,每个事务必须等待磁盘完全旋转.你可以在这里阅读完整的解释:
http://www.sqlite.org/faq.html#q19
实际上,SQLite很容易在普通的台式计算机上每秒执行50,000或更多INSERT语句.但它每秒只会进行几十次交易.交易速度受磁盘驱动器转速的限制.事务通常需要两个完整的磁盘盘旋转,这在7200RPM磁盘驱动器上限制您每秒约60个事务.
将您的时间与上述平均值进行比较:每秒50,000次=>应该花费2m 00秒.这比你的时间快一点.
事务速度受磁盘驱动器速度的限制,因为(默认情况下)SQLite实际上等待,直到事务完成之前数据确实安全地存储在磁盘表面上.这样,如果您突然断电或者操作系统崩溃,您的数据仍然是安全的.有关详细信息,请阅读SQLite中的原子提交.
默认情况下,每个INSERT语句都是自己的事务.但是如果用BEGIN ... COMMIT包围多个INSERT语句,则所有插入都被分组到一个事务中.提交事务所需的时间在所有随附的insert语句中分摊,因此每个insert语句的时间大大减少.
下一段中有一些提示可以尝试加速插入:
另一种选择是运行PRAGMA synchronous = OFF.此命令将导致SQLite不等待数据到达磁盘表面,这将使写入操作看起来更快.但是,如果在事务中间断电,则数据库文件可能会损坏.
我一直认为SQLite是为"简单的东西"而设计的,在我看来,600万条记录对于像MySQL这样的真实数据库服务器来说是一项工作.
计算具有如此多记录的SQLite表中的记录可能需要很长时间,仅为了您的信息,而不是使用SELECT COUNT(*),您总是可以使用非常快的SELECT MAX(rowid),但如果你正在删除该表中的记录.
编辑.
正如Mike Woodhouse所说,在插入记录后创建索引应该加速整个事情,这是其他数据库中的常见建议,但不能确定它在SQLite中是如何工作的.
您可能尝试的一件事是在插入数据后创建索引- 通常,数据库在单个操作中构建索引要比在每次插入(或事务)后更新索引要快得多.
我不能说它肯定会与SQLite一起使用,但因为它只需要两行来移动它值得尝试.
我也想知道600万行事务是否会走得太远 - 您是否可以更改代码以尝试不同的事务大小?说100,1000,10000,100000?有"甜蜜点"吗?
归档时间: |
|
查看次数: |
9513 次 |
最近记录: |