es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Oracle SQL (Pro*C): conociendo el número de filas de un select de antemano

En un archivo Pro*C, tengo un patrón de búsqueda como este:

EXEC SQL BEGIN DECLARE SECTION;
    typedef struct my<em>row</em>t
    {
        unsigned field1;
        unsigned field2;
    } my_row;
EXEC SQL END DECLARE SECTION;

void do<em>query()
{
    EXEC SQL BEGIN DECLARE SECTION;
        struct my</em>row* buffer;
        unsigned buffer_size;
    EXEC SQL END DECLARE SECTION;

buffer_size = /* algún límite superior relacionado con el número de filas a buscar */;
buffer = (my_row*)malloc(buffer_size * sizeof(my_row));

// Crear my_cursor basado en alguna consulta de selección
// ...
// y ahora:

EXEQ SQL FOR :buffer_size FETCH my_cursor INTO :buffer;
unsigned number_of_fetched_rows = sqlca.sqlerrd[2];

// En este punto, con solo una búsqueda, tengo todas las filas
}

El problema es que, a veces, no se puede estimar un límite superior adecuado. Me refiero a consultas que no devolverán más de unos miles de filas, pero no quiero asignar almacenamiento para, por ejemplo, 5000 filas cuando una consulta particular para una entrada particular solo le dará 500.

¿Existe alguna forma de saber de manera eficiente, antes de hacer la primera búsqueda (por ejemplo, justo después de abrir el cursor), el número de filas a buscar sin ejecutar ninguna consulta de conteo (por razones de rendimiento)?

Mi objetivo es “buscar todo” en un solo pase de la manera más eficiente posible.

Creo que se puede hacer con tablas/registros PL/SQL, pero no sé cómo “guardar” o extraer el contenido de una tabla PL/SQL en un búfer propio utilizando la sintaxis de Pro*C.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Desafortunadamente, no es posible conocer el número exacto de filas a recuperar sin ejecutar una consulta count(*) o sin recuperar todas las filas. Sin embargo, puedes usar un arreglo dinámico para asignar memoria según sea necesario mientras recuperas las filas.

    En Pro*C, puedes usar la instrucción define para asignar memoria de forma dinámica para el arreglo. Aquí hay un ejemplo:

    EXEC SQL BEGIN DECLARE SECTION;
        typedef struct my_row_t
        {
            unsigned field1;
            unsigned field2;
        } my_row;
    EXEC SQL END DECLARE SECTION;
    
    void do_query()
    {
        EXEC SQL BEGIN DECLARE SECTION;
            struct my_row* buffer;
        EXEC SQL END DECLARE SECTION;
    
        // Crear my_cursor basado en alguna consulta select
        // ...
    
        // obtener el número total de filas en el conjunto de resultados
        EXEC SQL DECLARE my_cursor DYNAMIC SCROLL CURSOR FOR select * from my_table;
        EXEC SQL OPEN my_cursor;
        EXEC SQL FETCH ABSOLUTE 0 FROM my_cursor;
        long int total_rows = sqlca.sqlerrd[2];
        EXEC SQL CLOSE my_cursor;
    
        // asignar memoria para el buffer
        buffer = (my_row*)malloc(total_rows * sizeof(my_row));
    
        // recuperar todas las filas
        EXEC SQL DECLARE my_cursor DYNAMIC SCROLL CURSOR FOR
                select col1, col2 from my_table;
        EXEC SQL OPEN my_cursor;
        for (int i = 0; i < total_rows; i++) {
            EXEC SQL FETCH NEXT FROM my_cursor INTO :buffer[i].field1, :buffer[i].field2;
        }
        EXEC SQL CLOSE my_cursor);
    }
    

    Este enfoque asignará memoria solo para el número necesario de filas, pero podría potencialmente causar fragmentación de memoria si el tamaño del conjunto de resultados varía ampliamente. Otra alternativa es usar una tabla temporal para almacenar el conjunto de resultados y recuperar desde ella. Este enfoque requeriría un paso adicional para poblar la tabla temporal, pero permitiría recuperar todas las filas de manera eficiente sin asignar demasiada memoria.

Comments are closed.