2008-09-24 13 views
8

Tengo un script SQL que quiero mostrar mensajes de progreso a medida que se ejecuta. Tener mensajes de salida entre sentencias SQL es fácil, sin embargo, llevo mucho tiempo ejecutando INSERT INTO SELECTs. ¿Hay alguna forma de tener una instrucción de selección de mensajes de salida a medida que avanza, por ejemplo, después de cada 1000 filas, o cada 5 segundos?¿Cómo puedo generar mensajes de progreso desde una instrucción SELECT?

Nota: Esto es para SQL Anywhere, pero las respuestas en cualquier lenguaje SQL va a estar bien.

Respuesta

3

SQL sí mismo no tiene provisión para este tipo de cosas. Cualquier forma de hacerlo implicaría hablar directamente con el motor de la base de datos, y no sería estándar en las bases de datos.

2

Ciertamente no hay solución SQL estándar para esto. Lamento estar cargado de fatalidades, pero no he visto nada que pueda hacer esto en Oracle, SQL Server, Sybase o MySQL, por lo que no sería muy optimista para SQLAnywhere.

+0

Oracle tiene 'v $ session_longops': http://docs.oracle.com/cd/E11882_01/server.112/e25513/dynviews_3022.htm#i1415618 –

0

En la remota posibilidad de que estés usando sapo, se puede generar un conjunto de instrucciones INSERT de una mesa y configurarlo para que se comprometan a una frecuencia de entrada del usuario. Puede modificar sus secuencias de comandos un poco y luego ver cuánto de los nuevos datos se han comprometido sobre la marcha.

+0

No, no usa Toad. Si fuera fácil dividir las instrucciones INSERT, podría obtener una actualización de progreso entre ellas, pero eso no funciona para las instrucciones INSERT INTO SELECT. –

2

estoy de acuerdo que SQL no tiene una forma de hacerlo directamente. Una forma podría ser solo insertar el TOP 1000 a la vez y luego imprimir su mensaje de estado. Luego repita esto según sea necesario (en un bucle de algún tipo). La desventaja es que necesitaría una forma de hacer un seguimiento de dónde se encuentra.

Debo señalar que este enfoque no será tan eficiente como se acaba de hacer un gran INSERT

+0

esta es la forma en que lo he hecho antes. Afirma que es mucho más lento. –

+0

Podría intentarlo de todos modos. agregue 'where row_id between ...' a la tabla principal en la unión, luego bucle para cada partición. Puedo lidiar con que sea un poco más lento, así que tendremos que ver cuánto más lento es. –

3

Realmente la idea de progreso con operaciones basadas en conjunto (que es lo que utiliza una base de datos relacional) no sería demasiado útil, al menos no como se muestra con una barra de progreso (porcentaje hecho versus total). En el momento en que el optimizador descubrió lo que tenía que hacer y realmente entendió el costo total de la operación, ya ha completado una parte importante de la operación. Las pantallas de progreso están realmente destinadas a operaciones iterativas en lugar de operaciones de conjunto.

Eso está hablando acerca de su ejecución general de instrucción SELECT. Para inserciones que son declaraciones separadas, hay varias formas de hacerlo desde el remitente al monitorear la tasa de consumo de las declaraciones. Si son inserciones masivas (seleccionar en, insertar desde y similares), entonces realmente tiene el mismo problema que describí anteriormente. Las operaciones de configuración se agrupan de forma que hacen que un tipo de barra de progreso no tenga sentido.

+0

Hmm, ese es un buen punto, no lo había pensado de esa manera. –

5

No hay manera de recuperar el estado de ejecución de una consulta individual. Ninguno de los motores de base de datos convencionales proporciona esta funcionalidad.
Por otra parte, una sobrecarga medible sería generada desde cualquier aplicación avances fueron uno de existir, por lo que si una consulta ya está tomando una incómoda tanto tiempo que desea mostrar el progreso, causando desaceleración adicional al mostrar dijo que el progreso podría no ser un diseño Gol.
Puede resultar útil esta article on estimating SQL execution progress, aunque sus implicaciones prácticas son limitadas.

+0

Gracias por el enlace, ¡es una lectura bastante interesante! –

+0

Pensé lo mismo, pero un poco de teoría demasiado para ser particularmente útil, creo. Es una lástima que no haya ningún tipo de sugerencia de consulta "con estadísticas" en cualquier rdbms que conozcamos, pero pensando en ello, la implementación sería tan difícil y consumiría tantos recursos que supongo que no es sorprendente. – Grank

+0

"* Ninguno de los motores de base de datos principales proporciona esta funcionalidad * - eso no es cierto. Oracle tiene' v $ session_longops': http://docs.oracle.com/cd/E11882_01/server.112/e25513/dynviews_3022.htm# i1415618 –

3

estoy en el equipo de desarrollo de SQL Anywhere motor y actualmente no hay manera de hacer esto. No puedo prometer nada, pero estamos considerando agregar este tipo de funcionalidad a una versión futura.

0

Se puede simular el efecto de sus usuarios midiendo el tiempo de varias carreras, y luego tener un avance barra de progreso en los registros promedio/segunda categoría.

Las únicas otras formas serán

1 - consulte la API de su motor de base de datos para ver si se hace ninguna provisión para que

o

2 - Divida su INSERT en muchos más pequeños declaraciones, e informar sobre ellas sobre la marcha. Pero eso tendrá un impacto significativo en el rendimiento negativo.

0

Si necesita tenerlo o se muere, para insertarlo, actualizarlo, eliminarlo puede usar alguna lógica de activación con variables db, y de vez en cuando hace sql para recuperar datos variables y mostrar algún progreso al usuario.

Si no lo quiere usar, puedo escribir un ejemplo y enviarlo.

1

Un pensamiento podría tener otro proceso separado cuente el número de filas en la tabla donde se realiza el inserto para determinar qué porcentaje de ellas ya existen. Esto, por supuesto, requeriría que usted sepa el total al final. Esto probablemente solo estaría bien si esto no le preocupa demasiado la carga del servidor.

+0

Suponiendo que está utilizando una forma débil de ácido que le permite ver los resultados a mitad de transacción que funcionarían, sí. –

2

Esto es lo que yo haría (sintaxis/SQL Server de Sybase):

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' 

O usted podría hacerlo sobre la base de la identificación (asume Id es un número):

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

Tropezamos con este viejo hilo buscando algo más. No estoy de acuerdo con la idea de que no queremos información de progreso solo porque es una operación establecida. Los usuarios a menudo tolerarán incluso una larga espera si saben cuánto tiempo es.

Esto es lo que sugiero:

Cada vez que esto pasa, ingrese el número de filas insertadas y el tiempo total, a continuación, agregar un paso al comienzo de ese proceso para consultar ese registro y calcular un tiempo total estimado. Si basa su estimación en las últimas ejecuciones, debería poder presentar una buena conjetura aceptable para el tiempo de espera para que la cosa termine.

Cuestiones relacionadas