8

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

注意:这适用于 SQL Anywhere,但任何 SQL 方言的答案都可以。

4

12 回答 12

5

无法检索单个查询的执行状态。主流数据库引擎都没有提供此功能。
此外,如果存在任何进度实现,都会产生可测量的开销,因此,如果查询已经花费了非常长的时间,以至于您想要显示进度,那么通过显示所述进度来导致额外的减速可能不是设计目标。
您可能会发现这篇关于估计 SQL 执行进度的文章很有帮助,尽管它的实际意义有限。

于 2008-09-24T19:59:34.833 回答
3

SQL 本身并没有对这种事情的规定。这样做的任何方式都将涉及直接与数据库引擎对话,并且不会是跨数据库的标准。

于 2008-09-24T19:49:53.407 回答
3

确实,使用基于集合的操作(这是关系数据库使用的)进行进度的想法并没有太大帮助,至少不像进度条显示的那样(完成百分比与总数)。当优化器弄清楚它需要做什么并真正了解操作的全部成本时,您已经完成了大部分操作。进度显示实际上是用于迭代操作而不是设置操作。

那是在谈论您的一般 SELECT 语句执行。对于作为单独语句的插入,提交者有各种方法可以通过监控语句的消耗率来做到这一点。如果它们是批量插入(select into、insert from 等),那么您确实遇到了与我上面描述的相同的问题。集合操作的批处理方式使得进度条类型的显示有点毫无意义。

于 2008-09-24T19:55:45.327 回答
3

我在 SQL Anywhere 引擎开发团队工作,目前没有办法做到这一点。我不能保证任何事情,但我们正在考虑将这种类型的功能添加到未来的版本中。

于 2008-09-24T20:12:02.013 回答
2

对此当然没有 SQL 标准的解决方案。很抱歉被厄运,但我还没有看到任何东西可以在 Oracle、SQL Server、Sybase 或 MySQL 中做到这一点,所以我不会对 SQLAnywhere 抱太大希望。

于 2008-09-24T19:50:45.450 回答
2

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

我应该注意到,这种方法不会像只做一个大 INSERT 那样有效

于 2008-09-24T19:55:16.437 回答
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'

或者您可以根据 ID 执行此操作(假设 Id 是一个数字):

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'
于 2008-10-02T12:13:57.793 回答
1

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

于 2008-10-02T01:31:48.307 回答
0

您可以通过计时多次运行来模拟用户的效果,然后以平均记录/秒的速度前进进度条。

唯一的其他方法是

1 - 请参阅您的数据库引擎的 API 以查看它是否为此做出任何规定

或者

2 - 将您的 INSERT 分解为许多较小的语句,并随时报告它们。但这将对性能产生重大的负面影响。

于 2008-09-24T20:16:07.790 回答
0

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

于 2008-09-24T19:52:03.793 回答
0

如果你需要它或者你死了,对于插入、更新、删除,你可以使用一些带有 db 变量的触发逻辑,并且你可以不时地执行 sql 来检索变量数据并向用户显示一些进度。

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

于 2008-10-02T01:10:14.067 回答
0

偶然发现这个旧线程正在寻找其他东西。我不同意我们不希望仅仅因为它是一个集合操作而需要进度信息的想法。如果用户知道等待多长时间,他们通常会容忍甚至长时间的等待。

这是我的建议:

每次运行时,记录插入的行数和总时间,然后在该过程的开头添加一个步骤来查询该日志并计算估计的总时间。如果您的估计基于最后一次运行,您应该能够对事情完成的等待时间提出一个可接受的良好猜测。

于 2014-02-05T21:21:05.040 回答