2008-09-24 59 views
8

我有一个SQL脚本,我想在运行时输出进度消息。让它在SQL语句之间输出消息很容易,但是我有一些运行时间很长的INSERT INTO SELECTs。有没有办法让select语句输出消息,例如每1000行或每隔5秒?如何从SELECT语句输出进度消息?

注意:这是针对SQL Anywhere的,但任何SQL方言中的回答都可以。

回答

3

SQL本身没有提供这种东西。这样做的任何方式都会涉及到直接与数据库引擎直接对话,而不是跨数据库的标准。

2

这肯定没有SQL标准的解决方案。对不起,我们没有看到任何可以在Oracle,SQL Server,Sybase或MySQL中执行此操作的东西,所以我不会对SQLAnywhere太满意。

+0

Oracle有`v $ session_longops`:http://docs.oracle.com/cd/E11882_01/server.112/e25513/dynviews_3022.htm#i1415618 – 2014-02-05 21:45:32

0

如果不使用Toad,您可以从表中生成一组INSERT语句,并将其配置为以用户输入频率进行提交。您可以稍微修改您的脚本,然后查看您提交的新数据的数量。

+0

不,不使用蟾蜍。如果要很容易地对INSERT语句进行分区,那么我可以在它们之间获得进度更新,但对于INSERT INTO SELECT语句不起作用。 – 2008-09-24 20:18:17

2

我同意SQL没有办法直接做到这一点。一种方法可能是一次只插入TOP 1000,然后打印状态消息。然后根据需要继续重复此操作(在某种类型的循环中)。缺点是你需要一种方法来跟踪你的位置。

我要指出,这种做法将无法做到高效的只是做一个大的INSERT

+0

这是我之前完成的方式。确认它的速度较慢。 – 2008-09-24 20:14:37

+0

无论如何,我可能会试一试。将'where ...之间的row_id'添加到联接中的主表中,然后循环每个分区。我可以处理它慢一点,所以我们不得不看它慢多少。 – 2008-09-24 20:22:57

3

真正的基于集合运算进步的理念(这是一个关系型数据库使用),不会太有帮助,至少没有显示进度条(完成百分比与总数)。当优化器找出需要做什么并真正理解操作的全部成本时,您已经完成了大部分操作。进度显示实际上是用于迭代操作而不是设置操作。

这是关于您的一般SELECT语句执行。对于插入是单独的语句,通过监视语句的消费率,提交者可以通过各种方式执行此操作。如果他们是批量插入(选择,插入等),那么你真的有同样的问题,我上面描述。设置操作的批处理方式使进度条类型的显示有些没有意义。

+0

嗯,这是一个好点,我没有这样想过。 – 2008-09-24 20:15:53

5

无法检索单个查询的执行状态。主流数据库引擎都没有提供这种功能。
此外,任何执行过程中都会产生可测量的开销,因此如果查询已经花费了很长时间的令人不快的时间,以至于您想要显示进度,则通过显示所述进度而导致额外的减速可能不是设计目标。
您可能会发现这article on estimating SQL execution progress有帮助,虽然它的实际影响是有限的。

+0

感谢您的链接,其相当有趣的阅读! – 2008-09-24 20:13:54

3

我在SQL Anywhere引擎开发团队中,目前没有办法执行此操作。我无法承诺任何内容,但我们正在考虑将此类功能添加到未来版本中。

0

您可以通过计时几次运行来模拟用户的影响,然后以平均记录/秒的速率推进进度条。

其他唯一的办法将是

1 - 请参考您的数据库引擎的API,看它是否让任何规定,

2 - 打破你的INSERT分成许多​​小陈述,并随时向他们报告。但是这会对性能产生显着的负面影响。

0

如果你需要拥有它或者你死了,对于插入,更新,删除,你可以使用一些触发器逻辑和db变量,并且每次你做sql来检索变量数据并向用户显示一些进度。

如果你不想使用它,我可以写一个例子并发送它。

1

一个想法可能会有另一个单独的进程计算表中插入的行数,以确定它们已经存在的百分比。这当然需要你知道最后的总数。如果你不太担心服务器负载,这可能只是没关系。

2

这里就是我会做(的Sybase/SQL Server语法):

DECLARE @total_rows int 

SELECT @total_rows = count(*) 
FROM Source_Table 

WHILE @total_rows > (SELECT count(*) FROM Target_Table) 
BEGIN 
    SET rowcount 1000 

    print 'inserting 1000 rows' 

    INSERT Target_Table   
    SELECT * 
    FROM Source_Table s 
    WHERE NOT EXISTS(SELECT 1 
         FROM Target_Table t 
         WHERE t.id = s.id) 
END 

set rowcount 0 
print 'done' 

或者你可以根据标识(假设标识是一个数字)做到这一点:

DECLARE @min_id int, 
     @max_id int, 
     @start_id int, 
     @end_id int 

SELECT @min_id = min(id) , 
     @max_id = max(id) 
FROM Source_Table 

SELECT @start_id = @min_id , 
     @end_id = @min_id + 1000 

WHILE @end_id <= @max_id 
BEGIN 

    print 'inserting id range: ' + convert(varchar,@start_id) + ' to ' + convert(varchar,@end_id) 

    INSERT Target_Table   
    SELECT * 
    FROM Source_Table s 
    WHERE id   BETWEEN @start_id AND @end_id 

    SELECT @start_id = @end_id + 1, 
      @end_id = @end_id + 1000 
END 

set rowcount 0 
print 'done' 
0

在此绊倒老线索寻找别的东西。我不同意这样一个观点,即我们不想仅仅因为它是一套操作而需要进度信息。如果用户知道它有多长时间,用户往往会忍受很长时间的等待。

这里是我的建议:

这个运行每次,日志插入的行总时间数,然后在该过程的开头添加一个步骤来查询日志和计算估算总时间。如果您根据最后一次运行估算,您应该能够为该项目完成的等待时间提供可接受的良好猜测。