【发布时间】:2014-01-03 03:38:01
【问题描述】:
我需要定期将大型(数十万行)tsv 文件导入到多个相关的 SQL Server 2008 R2 表中。
输入文件看起来像这样(实际上它更复杂,数据性质不同,但我这里的类似):
January_1_Lunch.tsv
+-------+----------+-------------+---------+
| Diner | Beverage | Food | Dessert |
+-------+----------+-------------+---------+
| Nancy | coffee | salad_steak | pie |
| Joe | milk | soup_steak | cake |
| Pat | coffee | soup_tofu | pie |
+-------+----------+-------------+---------+
请注意,一列包含一个字符分隔列表,需要对其进行预处理才能将其拆分。
模式是高度规范化的——每条记录都有多个多对多外键关系。这里没有什么不寻常的......
Meals
+----+-----------------+
| id | name |
+----+-----------------+
| 1 | January_1_Lunch |
+----+-----------------+
Beverages
+----+--------+
| id | name |
+----+--------+
| 1 | coffee |
| 2 | milk |
+----+--------+
Food
+----+-------+
| id | name |
+----+-------+
| 1 | salad |
| 2 | soup |
| 3 | steak |
| 4 | tofu |
+----+-------+
Desserts
+----+------+
| id | name |
+----+------+
| 1 | pie |
| 2 | cake |
+----+------+
每个输入列最终都指向一个单独的表。
这似乎是一个不必要的复杂模式——为什么不只使用一个与输入匹配的表呢?但是考虑到一个用餐者可能进入餐厅并只点了一杯饮料或甜点,在这种情况下会有很多空行。考虑到该数据库最终将存储数亿条记录,这似乎是对存储的不良使用。我还希望能够生成仅针对饮料、仅针对甜点等的报告,并且我认为使用单独的表格会表现得更好。
订单在这样的关系表中被跟踪:
BeverageOrders
+--------+---------+------------+
| mealId | dinerId | beverageId |
+--------+---------+------------+
| 1 | 1 | 1 |
| 1 | 2 | 2 |
| 1 | 3 | 1 |
+--------+---------+------------+
FoodOrders
+--------+---------+--------+
| mealId | dinerId | foodId |
+--------+---------+--------+
| 1 | 1 | 1 |
| 1 | 1 | 3 |
| 1 | 2 | 2 |
| 1 | 2 | 3 |
| 1 | 3 | 2 |
| 1 | 3 | 4 |
+--------+---------+--------+
DessertOrders
+--------+---------+-----------+
| mealId | dinerId | dessertId |
+--------+---------+-----------+
| 1 | 1 | 1 |
| 1 | 2 | 2 |
| 1 | 3 | 1 |
+--------+---------+-----------+
请注意,Food 的记录更多,因为输入包含那些被拆分为多个记录的讨厌的小列表。这是使用单独的表格有帮助的另一个原因。
所以问题是,将文件中的数据获取到您在上面看到的架构中的最有效方法是什么?
我考虑过的方法:
- 逐行解析 tsv 文件,同时执行插入操作。无论是否使用 ORM,这似乎都需要多次访问数据库,而且速度会非常慢。
- 将 tsv 文件解析为内存中的数据结构,或磁盘上与架构相对应的多个文件。然后使用 SqlBulkCopy 导入每一个。虽然事务较少,但它似乎比简单地执行大量插入更昂贵,因为必须缓存大量数据或执行大量写入磁盘。
- 根据How do I bulk insert two datatables that have an Identity relationship 和Best practices for inserting/updating large amount of data in SQL Server 2008,将 tsv 文件导入临时表,然后合并到模式中,使用 DB 函数进行预处理。这似乎是最好的选择,但我认为验证和预处理可以在 C# 或其他任何东西中更有效地完成。
还有其他可能性吗?
该架构仍在开发中,因此如果最终成为症结,我可以对其进行修改。
【问题讨论】:
-
4.使用 SSIS........
-
我建议您重新考虑将饮料、餐点和甜点分开,并考虑为这些项目设置一个单独的桌子,并用代码表示“类型”或“类别”。为什么?考虑一下添加“starters”或“side orders”的业务变更,添加新类别比添加全新表要容易得多。不要过度担心空间效率低下;获得一个好的模型更为重要。
-
@MitchWheat - 我感觉 SQL Server 集成服务可能很有用,但对它知之甚少。你能再具体一点吗?我们在这里谈论 ETL 吗?
-
@Rikalous - 如果我们谈论的是数以亿计的充满空值的行,我们在哪里划定界限来确定什么是过度担忧和什么是谨慎的?
标签: sql-server sql-server-2008-r2 foreign-key-relationship bulkinsert sqlbulkcopy