我正在处理一个控制台应用程序,在该应用程序中,它从一个表中获取100万条记录,该表位于不同的服务器中并存储到数据表中并将DataTable发送到SQL并使用合并插入/更新到我们的表中声明。要获取数据需要25分钟,插入需要20分钟,我使用的是SQL-Server management studio-2012。
我想通过在每10000条记录中显示“插入/更新10000条记录”或者以10秒的特定时间延迟来显示前屏幕上的信息。
有没有办法使用SQL(更新的每10000条记录,需要向App发送消息)或通过控制台应用程序实现此目的。以下是我使用的存储过程。
ALTER PROCEDURE [dbo].[sp_Data_Inserting_In_To_QueueTable]
-- Add the parameters for the stored procedure here
@Values AS [dbo].[Type_Table] READONLY
AS
BEGIN
SET NOCOUNT ON;
;WITH CTE_data_codes AS(
select [NO], [ID], [Name], [Code] from @SearchValues where [No] != '0'
)
MERGE tbl__QueueTable_Codes AS t
-- Values is the temp table in which data is coming from the console application
USING CTE_data_codes AS s
ON (s.Code = t.Code and s.NO = t.NO and s.ID = t.ID)
WHEN NOT MATCHED by target
--Newly added values in Values has been updated in tbl__QueueTable_Codes
THEN INSERT(NO, Name, ID, Code, Deleted)
VALUES(s.[NO], s.[Name], s.[ID], s.[Code], 0)
WHEN NOT MATCHED by source
--It means the value has been deleted in Value, hence we put a flag for deleted ones as '1'.
THEN UPDATE
SET t.Deleted = 1;
END
答案 0 :(得分:0)
如果您不需要插入/合并是顺序的,则应该为插入添加并行性。
在我的情况下,我处理AVL
gps数据4000 records/min
每条记录需要找到near_road
以了解汽车的位置。查找道路的功能是线性时间10ms
,因此4000
记录为40 sec
。
因此,我没有为4000条记录发送INSERT
次查询,而是使用C#
发送4x1000
,而是花费大约10秒钟。
在这个QUESTION中,您可以看到我如何将avl拆分为范围并发送到存储过程,其中一个答案是建议在C#中使用Parallel.ForEach
答案 1 :(得分:-1)
这是可能的。我不确定你用什么来实际从数据库中获取数据,但SqlDataReader类实际上是一个只进行的流,它逐行处理查询输出。您可以通过将方法包装在接受委托作为参数的类中来监视计数并调用每次获取另一个 N 行时打印进度的委托(Action)。
以下是我看到的一个示例(伪代码,从未实际检查过它):
public class ReadWriteWithProgress {
public List<ClassWeAreReading> ReadData(Action<int> rowCountReporter) {
List<ClassWeAreReading> result = new List<ClassWeAreReading>();
using (SqlConnection connection = new SqlConnection("Server=localhost;Integrated Security=true;Initial Catalog=MyDatabase;"))
{
connection.Open();
var queryToExecute = "SELECT Id, Name FROM dbo.Table";
using (SqlCommand command = new SqlCommand(queryToExecute, connection))
{
using (SqlDataReader dataReader = command.ExecuteReader())
{
if (dataReader != null) {
int rowCounter = 0;
while (dataReader.Read()) {
var intermediateResult = new ClassWeAreReading();
intermediateResult.Id = (int) dataReader["Id"];
intermediateResult.Name = dataReader["Name"].ToString();
rowCounter++;
if (rowCounter % 1000 == 0) {
if (rowCountReporter != null) {
rowCountReporter (rowCounter);
}
}
result.Add(intermediateResult);
}
}
}
}
}
}
public void LoadData(List<ClassWeAreReading> dataToLoad, Action<int> rowCountReporter) {
int rowCounter = 0;
// Iterate through the list (it might be IEnumerable or any other kind of collection you can iterate through) and use the callback in the same manner as above
// ...
rowCounter++;
if (rowCounter % 1000 == 0) {
if (rowCountReporter != null) {
rowCountReporter (rowCounter);
}
}
// ...
}
}
// Then you need this kind of method to use as a callback:
private static void PrintRowCount(int rowCount){
Console.WriteLine("{0} rows transferred...", rowCount);
}
private static void PrintUpdateRowCount(int rowCount){
Console.WriteLine("{0} rows written...", rowCount);
}
// And finally you can start your stuff and pass in the method:
static void Main(string[] args)
{
var readerWithProgress = new ReadWriteWithProgress();
var result = readerWithProgress.ReadData(PrintRowCount);
readerWithProgress.LoadData(result, PrintUpdateRowCount);
}