hola
estos temas lo vi para mi examen de titulo, veo dos planos acá

1. el tuning propiamente tal de postgres (para solicitudes en paralelo, y también uso de indices, etc),
ya te han dado algunas consideraciones a tener...

2. usar código eficiente en java

te comparto lo que desarrolle como prueba de concepto, de manera que te hagas una idea,
(el primero permitió una mejora sustancial respecto del código ineficiente)

el segundo aun mas , pero con mas consumo de memoria. (donde se ejecuta java)


código eficiente sin hilos
...

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.SQLException;

import java.util.Random;

import java.lang.management.ManagementFactory;

import java.lang.management.MemoryMXBean;

public class EfficientProcessingExample {

public static void main(String[] args) {

String jdbcUrl = "jdbc:postgresql://localhost:5432/carrera";

String username = "admin";

String password = "l3r0l3r0";

try {

Connection connection = DriverManager.getConnection(jdbcUrl, username, password);

PreparedStatement preparedStatement = connection.prepareStatement(

"UPDATE curso SET promedio = ?, aprobado = ? WHERE indice = ?;"

);

int totalRecords = 40000;

Random random = new Random();

long startTime = System.currentTimeMillis();

for (int idx = 1; idx <= totalRecords; idx++) {

int nota1 = random.nextInt(7) + 1;

int nota2 = random.nextInt(7) + 1;

int nota3 = random.nextInt(7) + 1;

double promedio = (nota1 + nota2 + nota3) / 3.0;

boolean aprobado = promedio > 4.0;

preparedStatement.setDouble(1, promedio);

preparedStatement.setBoolean(2, aprobado);

preparedStatement.setInt(3, idx);

preparedStatement.addBatch(); // Agregar la consulta al lote

if (idx % 1000 == 0) {

preparedStatement.executeBatch(); // Ejecutar el lote de consultas cada 1000 registros

preparedStatement.clearBatch(); // Limpiar el lote

}

}

preparedStatement.executeBatch(); // Ejecutar cualquier consulta restante en el lote

preparedStatement.close(); // Cerrar la declaración

long endTime = System.currentTimeMillis();

long elapsedTime = endTime - startTime;

System.out.println("Tiempo de ejecución: " + elapsedTime + " ms");

// Obtener información sobre el uso de memoria

MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();

long usedMemory = memoryMXBean.getHeapMemoryUsage().getUsed();

String sizeUnit;

double sizeValue;

if (usedMemory < 1024) {

sizeValue = usedMemory;

sizeUnit = "bytes";

} else if (usedMemory < 1024 * 1024) {

sizeValue = (double) usedMemory / 1024;

sizeUnit = "KB";

} else if (usedMemory < 1024 * 1024 * 1024) {

sizeValue = (double) usedMemory / (1024 * 1024);

sizeUnit = "MB";

} else {

sizeValue = (double) usedMemory / (1024 * 1024 * 1024);

sizeUnit = "GB";

}

System.out.println("Uso de memoria: " + sizeValue + " " + sizeUnit);

connection.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}



...

código eficiente con hilos

...
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Random;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
public class EfficientProcessingWithThreadsExample {
    public static void main(String[] args) {
        String jdbcUrl = "jdbc:postgresql://localhost:5432/carrera";
        String username = "admin";
        String password = "l3r0l3r0";
        try {
            Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
            int totalRecords = 40000;
            EfficientProcessorThread[] threads = new EfficientProcessorThread[totalRecords];
            for (int idx = 1; idx <= totalRecords; idx++) {
                threads[idx - 1] = new EfficientProcessorThread(idx, connection);
                threads[idx - 1].start();
            }
            long startTime = System.currentTimeMillis();
            for (EfficientProcessorThread thread : threads) {
                thread.join();
            }
            long endTime = System.currentTimeMillis();
            long elapsedTime = endTime - startTime;
            // Obtener información sobre el uso de memoria
            MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
            long usedMemory = memoryMXBean.getHeapMemoryUsage().getUsed();
            String sizeUnit;
            double sizeValue;
            if (usedMemory < 1024) {
                sizeValue = usedMemory;
                sizeUnit = "bytes";
            } else if (usedMemory < 1024 * 1024) {
                sizeValue = (double) usedMemory / 1024;
                sizeUnit = "KB";
            } else if (usedMemory < 1024 * 1024 * 1024) {
                sizeValue = (double) usedMemory / (1024 * 1024);
                sizeUnit = "MB";
            } else {
                sizeValue = (double) usedMemory / (1024 * 1024 * 1024);
                sizeUnit = "GB";
            }
            System.out.println("Uso de memoria: " + sizeValue + " " + sizeUnit);             System.out.println("Tiempo de ejecución: " + elapsedTime + " ms");
            connection.close();
        } catch (SQLException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class EfficientProcessorThread extends Thread {
    private final int idx;
    private final Connection connection;
    private final Random random;
    public EfficientProcessorThread(int idx, Connection connection) {
        this.idx = idx;
        this.connection = connection;
        this.random = new Random();
    }
    @Override
    public void run() {
        try {
            int nota1 = random.nextInt(7) + 1;
            int nota2 = random.nextInt(7) + 1;
            int nota3 = random.nextInt(7) + 1;
            double promedio = (nota1 + nota2 + nota3) / 3.0;
            boolean aprobado = promedio > 4.0;
            PreparedStatement preparedStatement = connection.prepareStatement(                 "UPDATE curso SET promedio = ?, aprobado = ? WHERE indice = ?;"
            );
            preparedStatement.setDouble(1, promedio);
            preparedStatement.setBoolean(2, aprobado);
            preparedStatement.setInt(3, idx);
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}


...

el código ineficiente:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Random;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
public class InefficientProcessingExample {
    public static void main(String[] args) {
        String jdbcUrl = "jdbc:postgresql://localhost:5432/carrera";
        String username = "admin";
        String password = "l3r0l3r0";

        try {
            Connection connection = DriverManager.getConnection(jdbcUrl, username, password);             PreparedStatement preparedStatement = connection.prepareStatement(                 "UPDATE curso SET promedio = ?, aprobado = ? WHERE indice = ?;"
            );

            int totalRecords = 40000;
            Random random = new Random();

            long startTime = System.currentTimeMillis();

            for (int idx = 1; idx <= totalRecords; idx++) {
                int nota1 = random.nextInt(7) + 1;
                int nota2 = random.nextInt(7) + 1;
                int nota3 = random.nextInt(7) + 1;
                double promedio = (nota1 + nota2 + nota3) / 3.0;
                boolean aprobado = promedio > 4.0;

                preparedStatement.setDouble(1, promedio);
                preparedStatement.setBoolean(2, aprobado);
                preparedStatement.setInt(3, idx);
                preparedStatement.executeUpdate();
            }

            long endTime = System.currentTimeMillis();
            long elapsedTime = endTime - startTime;

            System.out.println("Tiempo de ejecución: " + elapsedTime + " ms");

            // Obtener información sobre el uso de memoria
            MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
            long usedMemory = memoryMXBean.getHeapMemoryUsage().getUsed();
            String sizeUnit;
            double sizeValue;

            if (usedMemory < 1024) {
                sizeValue = usedMemory;
                sizeUnit = "bytes";
            } else if (usedMemory < 1024 * 1024) {
                sizeValue = (double) usedMemory / 1024;
                sizeUnit = "KB";
            } else if (usedMemory < 1024 * 1024 * 1024) {
                sizeValue = (double) usedMemory / (1024 * 1024);
                sizeUnit = "MB";
            } else {
                sizeValue = (double) usedMemory / (1024 * 1024 * 1024);
                sizeUnit = "GB";
            }
            System.out.println("Uso de memoria: " + sizeValue + " " + sizeUnit);
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

....









El 08-01-24 a las 23:59, Jairo Graterón escribió:
Saludos lista

Hay un reto para crear un algoritmo en java para para recuperar valores de medición de temperatura de un archivo de texto y calcular la temperatura mínima, media y máxima por estación meteorológica https://www.morling.dev/blog/one-billion-row-challenge/

Pero se están haciendo implementaciones en otros lenguajes y por supuesto en bases de datos por ejemplo https://ftisiot.net/posts/1brows/ y https://rmoff.net/2024/01/03/1%EF%B8%8F%E2%83%A3%EF%B8%8F-1brc-in-sql-with-duckdb/

Ya inserté los mil millones de registros en mi máquina y al realizar la consulta
image.png
Tarda casi 2 minutos, así que seguí investigando como mejorar el tiempo y al encontrar estas otras pruebas https://gist.github.com/FranckPachot/50a6a491b85b0ddb3da6399d54653085 me llamó la atención ésta línea
select/*+ parallel(8) gather_plan_statistics*/

Revisando postgres tiene un parámetro para aumentar el número de workers en paralelo si la consulta lo necesita max_parallel_workers_per_gather

image.png
Mejoró bastante, 40 segundos menos.

*¿Qué otras optimizaciones se podrían realizar en postgres para disminuir el tiempo?*

Con  Apache Pinot tarda aprox 1.9s
https://hubertdulay.substack.com/p/1-billion-row-challenge-in-apache?r=46sqk&utm_campaign=post&utm_medium=web <https://hubertdulay.substack.com/p/1-billion-row-challenge-in-apache?r=46sqk&utm_campaign=post&utm_medium=web>

Otro tardó 20 segundos
https://twitter.com/_TylerHillery/status/1742971310123487429


Por supuesto eso depende de las especificaciones del equipo pero es interesante que compartan sus experiencias.

Las especificaciones de mi máquina son:
Ryzen 5 6 cores/12 Threads a 3.0ghz
Disco nvme KINGSTON
Ubuntu 22.04
Postgresql 14





Enrique Herrera Noya
--
+56 992303151
Red Hat Certified Engineer RHCE Nº100223072 (RH6.0)
Red Hat Certified System Administrato RHCSA Nº100223072 (RH6.0)
Red Hat Certified Technician (RHCT) Nº605010753835478 (RH5.0)
Novell Certified Linux Professional CLP 10
Red Hat Delivery Specialist -Container Platform Application Deployment I
Red Hat Delivery Specialist - Container Platform Administration I
RED HAT SPECIALIST
How to Sell Red Hat OpenShift for Infrastructure
How to Sell Red Hat OpenShift for Developers
Red Hat Sales Engineer Specialist - Container Platform
Red Hat Sales Engineer Specialist – Automation

Reply via email to