Skip to content
LakeBench
ProblemsCommunityPricing
Sign inStart practicing
Back
  1. Home
  2. Interview prep
  3. Connecting to a database safely

Python · Python for Data Pipelines

Connecting to a database safely

Mediumpython-46
databasesql-injectionconnection-poolingbulk-loadsqlalchemy

Question

How do you connect Python to a SQL database safely and efficiently?

Solution

Use parameterised queries, keep credentials out of code, open connections in a context manager, reuse them through a pool, read big results in pieces, and load in bulk. Each of those avoids a specific problem.

Parameterised queries

Never build SQL by pasting values into a string.

# unsafe: if name is  x'; DROP TABLE users; --  you have a problem
cur.execute(f"SELECT * FROM users WHERE name = '{name}'")

# safe: the driver sends the value separately from the SQL text
cur.execute("SELECT * FROM users WHERE name = %s", (name,))

The placeholder syntax depends on the driver (%s, ?, :name). The database treats the value as data, never as SQL, which blocks SQL injection. It also handles quoting and types for you.

Credentials

Read the host, user and password from environment variables or a secret manager, and never commit them to Git. Give the pipeline a database user with only the privileges it needs, and for extraction jobs, read-only access to a replica.

Close things properly

with engine.connect() as conn:
    result = conn.execute(text("SELECT ..."), {"d": run_date})

The with block closes the connection even if an error is raised. Leaked connections slowly use up the database's connection limit.

Pooling

Opening a connection is slow, so a pool (the one in SQLAlchemy's create_engine, for example) keeps a few open and reuses them. It matters most when code runs many small queries. Set the pool size with the database's max_connections in mind, particularly when many tasks run in parallel.

Large results

fetchall() loads everything into memory. Use fetchmany(10_000) in a loop, or a server-side cursor (stream_results=True in SQLAlchemy, or a named cursor in psycopg2), so the database streams rows to you.

Loading data in

Inserting row by row with INSERT is slow, because every statement is a network round trip. Use executemany with batches, or better, the bulk path of the database: COPY in Postgres (cursor.copy_expert or psycopg's copy), LOAD DATA in MySQL, or staged files in a warehouse. That can be 10 to 100 times faster. Wrap the load in a transaction, so a failure leaves nothing half-written.

🎯 Put this concept into practice

Solidify this answer with real hands-on interview drills in the browser studio.

Open related drill →
PreviousNext