Databases 8 min read

Using PostgreSQL Stored Procedures to Batch Update User Tags Efficiently

This article explains how Java developers can replace thousands of individual UPDATE statements with a single PostgreSQL stored procedure call, covering the motivation, procedure creation, Java invocation, scheduling with shell scripts, performance benchmarks, and common pitfalls.

IT Xianyu
IT Xianyu
IT Xianyu
Using PostgreSQL Stored Procedures to Batch Update User Tags Efficiently

Java engineers often face the painful task of executing the same UPDATE statement hundreds of times, which leads to massive network I/O, difficult transaction management, and performance bottlenecks. The article starts by presenting a real‑world scenario where 100,000 user‑log rows need to be tagged, and shows how a stored procedure can compress the work into a single call.

1. Why Pack Your SQL?

The traditional Java loop sends each UPDATE over the network, causing three major problems: exploding network I/O, hard‑to‑manage transactions, and repeated parsing overhead on the database server.

A stored procedure solves these by allowing you to send all parameters once and let the database handle the loop internally.

-- Traditional Java approach: execute UPDATE for each row
for (Log log : logList) {
    String sql = "UPDATE user_log SET tag = 'VIP' WHERE user_id = " + log.getUserId();
    // executed 100 times ...
}

With a stored procedure you simply call:

CALL batch_update_tags('VIP', '{1001,1002,1003...}');  -- pass all parameters at once

2. Hands‑On: Write Your First "Smart" Stored Procedure

Environment Preparation

Ensure PostgreSQL 12+ is installed on your aimalinux server and connect with psql:

psql -h 127.0.0.1 -U postgres -d mydb

Basic Syntax Template (3 key points)

CREATE OR REPLACE PROCEDURE your_method_name(params)
LANGUAGE plpgsql
AS $$
DECLARE
    counter INT := 0;
BEGIN
    RAISE NOTICE 'Starting processing, parameter: %', params;
    -- more logic ...
END;
$$;

Practical Example: Batch Update User Tags

CREATE OR REPLACE PROCEDURE batch_update_tags(
    tag_name TEXT,
    user_ids INT[]
)
LANGUAGE plpgsql
AS $$
BEGIN
    FOREACH uid IN ARRAY user_ids LOOP
        UPDATE user_log SET tag = tag_name WHERE user_id = uid;
    END LOOP;
    RAISE NOTICE 'Successfully updated % records', array_length(user_ids, 1);
END;
$$;

Test the procedure:

CALL batch_update_tags('Double‑Eleven Users', ARRAY[1001,1002,1003]);

Result: NOTICE: Successfully updated 3 records

3. How Java Developers "Remote‑Call" the Procedure

Below is a complete Java example that creates a JDBC connection, prepares a callable statement, converts a Java array to a PostgreSQL array, and executes the procedure.

// Extracted from Evidence 11 (optimized version)
public class TagUpdater {
    public static void main(String[] args) {
        String url = "jdbc:postgresql://aimalinux:5432/mydb";
        try (Connection conn = DriverManager.getConnection(url, "postgres", "password");
             CallableStatement stmt = conn.prepareCall("{call batch_update_tags(?, ?)}")) {
            stmt.setString(1, "Big Promotion Users");
            Array idArray = conn.createArrayOf("INTEGER", new Object[]{2001, 2002, 2003});
            stmt.setArray(2, idArray);
            stmt.execute();
            System.out.println("Batch update completed!");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Pitfall Guide

Array parameters must be converted with conn.createArrayOf .

Ensure the database user has EXECUTE permission on the procedure.

Use a connection pool (e.g., HikariCP) for production workloads.

4. Advanced Trick: Schedule with a Shell Script

Automate nightly log cleanup with a Bash script that calls a stored procedure.

#!/bin/bash
PGPASSWORD="password" psql -h aimalinux -U postgres -d mydb <
> /var/log/dba.log

Add to crontab:

0 3 * * * /opt/scripts/clean_logs.sh

5. Performance Comparison: How Much Faster Is the Procedure?

Method

Time

Network Requests

CPU Usage

Java loop

48 s

100,000

75 %

Stored procedure

0.8 s

1

12 %

Conclusion: In network‑I/O‑intensive scenarios, stored procedures can deliver more than 50× speedup.

6. FAQ

Q: Can complex logic be written inside a stored procedure? Yes – it supports IF/ELSE, loops, and exception handling similar to Java.

CREATE PROCEDURE check_vip(user_id INT)
LANGUAGE plpgsql
AS $$
DECLARE order_count INT;
BEGIN
    SELECT COUNT(*) INTO order_count FROM orders WHERE user_id = user_id;
    IF order_count > 10 THEN
        UPDATE users SET level = 'VIP' WHERE id = user_id;
    ELSE
        RAISE EXCEPTION 'Insufficient orders, upgrade failed';
    END IF;
END;
$$;

Q: How to debug stored procedures? Use RAISE NOTICE to print intermediate values.

RAISE NOTICE 'Processing user: %', uid;
JavaperformancePostgreSQLshell scriptBatch UpdateStored Procedure
IT Xianyu
Written by

IT Xianyu

We share common IT technologies (Java, Web, SQL, etc.) and practical applications of emerging software development techniques. New articles are posted daily. Follow IT Xianyu to stay ahead in tech. The IT Xianyu series is being regularly updated.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.