CodeGym /Courses /SQL SELF /Bulk Data Load Optimization

Bulk Data Load Optimization

SQL SELF
Level 24, Lesson 3
Available

Imagine you need to load a million rows of data. If you do it slowly, your server will be busy forever, users might notice the database slowing down, and—worst of all—your coffee might get cold before the process is done. Optimization helps you avoid overloading the server, cut down wait times, and minimize the chance of errors during the load.

Let’s start with the easy stuff, then move on to more advanced and sneaky tricks.

Disabling Indexes and Triggers

Indexes and triggers are awesome—they make our databases smart and responsive. But during a bulk data load, they can seriously slow things down, because the server tries to update indexes and run triggers for every single row you load.

To temporarily free your system from this burden, you can turn them off.

Example of disabling indexes and triggers:

-- Disabling triggers for the table
ALTER TABLE students DISABLE TRIGGER ALL;

-- Loading data
COPY students FROM '/path/to/students.csv' DELIMITER ',' CSV HEADER;

-- Enabling triggers back
ALTER TABLE students ENABLE TRIGGER ALL;

How does this work?

  1. We temporarily disable all triggers using the DISABLE TRIGGER ALL command.
  2. After loading the data, we turn triggers back on with ENABLE TRIGGER ALL.

Classic mistake: if you forget to re-enable triggers, some automation (like updating default fields) might not work right. So don’t forget to put everything back—just like turning off airplane mode on your phone.

Using Transactions

Transactions let you load all your data as if it’s one big operation. If something goes wrong, you can roll back the changes, and your database won’t turn into a mess of half-loaded data.

Example of using a transaction:

-- Start a transaction
BEGIN;

-- Load data
COPY courses FROM '/path/to/courses.csv' DELIMITER ',' CSV HEADER;

-- Commit changes
COMMIT;

Why is this faster?

When you load data without a transaction, the server commits changes after every row. With a transaction, the server does it just once at the end, saving a ton of time.

Disabling Integrity Checks

If you don’t need to check foreign keys or uniqueness constraints during the load, turn them off. Otherwise, the database will check every row, which slows things down.

Example of disabling integrity checks:

SET session_replication_role = 'replica';

-- Load data
COPY enrollments FROM '/path/to/enrollments.csv' DELIMITER ',' CSV HEADER;

SET session_replication_role = 'origin';

session_replication_role = 'replica' turns off data integrity checks (like uniqueness and FOREIGN KEY constraints).

Increasing Memory for Execution

Tuning PostgreSQL memory settings can boost data load performance. The key parameters are work_mem and maintenance_work_mem.

Example of increasing memory:

-- Increase memory
SET work_mem = '64MB';
SET maintenance_work_mem = '256MB';

-- Load data
COPY teachers FROM '/path/to/teachers.csv' DELIMITER ',' CSV HEADER;

What does this do?

  • work_mem is used for intermediate operations like sorts or hashing.
  • maintenance_work_mem affects index-related operations, like rebuilding them.

Tip: Be careful with memory increases, especially on systems with limited resources.

Prepping Data Before Loading

Prepping your data can seriously cut down load times. For example, if you have duplicate rows, filter them out ahead of time so PostgreSQL doesn’t waste time on junk data.

Example of cleaning data:

If you have a file with duplicate rows, you can use Python to remove them.

import pandas as pd

# Load CSV file
data = pd.read_csv('students.csv')

# Remove duplicates
data = data.drop_duplicates()

# Save clean CSV
data.to_csv('students_clean.csv', index=False)

Partitioning Data

If you’ve got a huge file, split it into several smaller ones. This lets PostgreSQL handle the data more efficiently.

Example:

Split the large_data.csv file into chunks of 1000 rows using Linux:

split -l 1000 large_data.csv chunk_

Then load them one by one:

COPY students FROM 'chunk_aa' DELIMITER ',' CSV HEADER;
COPY students FROM 'chunk_ab' DELIMITER ',' CSV HEADER;
-- And so on

Loading Data in the Background

If you can, use background processes to load data so you don’t overload your main database.

Tools like pg_cron help you schedule jobs.

Example: setting up a background load with pg_cron:

CREATE EXTENSION pg_cron;

SELECT cron.schedule('*/5 * * * *', $$COPY students FROM '/path/to/data.csv' DELIMITER ',' CSV HEADER$$);

Every 5 minutes, data from the file will be loaded into the table.

This is just an example, don’t actually do it like this! I just wanted to show you that PostgreSQL is super flexible, and you can manage data loads right from SQL scripts.

Gotchas

Some things to watch out for:

  • If you disable indexes and triggers, don’t forget to turn them back on! If you forget, you’ll be fixing errors after the load.
  • When bumping up memory settings, keep an eye on server resources: one greedy query can eat up all your RAM.
  • If you use transactions, make sure your data file doesn’t have critical errors. One mistake is enough to roll back the whole load.

Tips for the Future

Now you know how to optimize bulk data loads—from disabling indexes to using transactions. These skills will help you load data faster, save server resources, your nerves, your coffee, and keep users happy.

Next time you have to work with gigabyte-sized files, you’ll be ready!

2
Task
SQL SELF, level 24, lesson 3
Locked
Disabling Data Integrity Checks
Disabling Data Integrity Checks
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION