404 Not Found

404 Not Found


nginx

PostgreSQL Database Creation and Management

A database is PostgreSQL's top-level organizational unit — like a filing cabinet that can hold many drawers (tables).

1. What You'll Learn


2. A DevOps Engineer's Real Story

(1) The Pain: Three Environments, Three Character Sets

Charlie needs to create 3 databases for an e-commerce project, corresponding to the dev / staging / prod environments:

Charlie is unsure how to specify the character set and collation when creating a database, and doesn't know what a template database is.

(2) CREATE DATABASE to the Rescue

PostgreSQL's CREATE DATABASE lets you specify the character set, collation, and template at creation time:

SQL
-- Create databases with different locales for each environment
CREATE DATABASE shop_dev
    WITH ENCODING = 'UTF8'
    LC_COLLATE = 'en_US.utf8'
    LC_CTYPE = 'en_US.utf8'
    TEMPLATE = template1;

CREATE DATABASE shop_staging
    WITH ENCODING = 'UTF8'
    LC_COLLATE = 'en_US.utf8'
    LC_CTYPE = 'en_US.utf8';

CREATE DATABASE shop_prod
    WITH ENCODING = 'UTF8'
    LC_COLLATE = 'en_US.utf8'
    LC_CTYPE = 'en_US.utf8';

(3) The Payoff


3. Database Fundamentals

(1) PostgreSQL's Organizational Hierarchy

100%
graph TB
    PG[PostgreSQL Instance<br/>One running server] --> DB1[Database: shop_dev]
    PG --> DB2[Database: shop_staging]
    PG --> DB3[Database: shop_prod]
    DB1 --> SC1[Schema: public]
    SC1 --> T1[Table: users]
    SC1 --> T2[Table: orders]
    DB2 --> SC2[Schema: public]
    DB3 --> SC3[Schema: public]
Level Description Cardinality
Instance One running PostgreSQL server process 1 instance contains many databases
Database The top-level independent namespace 1 database contains many schemas
Schema A namespace within a database (default public) 1 schema contains many tables
Table A two-dimensional table storing data Tables belong to a schema
💡 Tip: Unlike MySQL, PostgreSQL's "database" is more like MySQL's "Schema". In PG you must specify a database when connecting, and you can't directly JOIN across databases (that needs FDW for cross-database queries, covered in a later lesson).


4. CREATE DATABASE

(1) Basic Syntax

SQL
CREATE DATABASE name
    [WITH]
    [OWNER = user_name]
    [TEMPLATE = template]
    [ENCODING = encoding_name]
    [LC_COLLATE = lc_collate]
    [LC_CTYPE = lc_ctype]
    [TABLESPACE = tablespace_name]
    [CONNECTION LIMIT = conn_limit]
    [IS_TEMPLATE = true | false];
Parameter Default Description
OWNER The executing user Database owner
TEMPLATE template1 The template copied when creating a new database
ENCODING Template's encoding Character encoding (UTF8 recommended)
LC_COLLATE Template's collation String sort order
LC_CTYPE Template's character classification Character classification (case/digits/etc.)
TABLESPACE Default tablespace Data-file storage location
CONNECTION LIMIT -1 (unlimited) Max concurrent connections
IS_TEMPLATE false Mark as a template database

▶ Example: Create a Basic Database

SQL
-- Create a simple database with default settings
CREATE DATABASE my_app;

-- Verify creation
\l

Output:

TEXT
CREATE TABLE

▶ Example: Create a Database with Full Parameters

SQL
-- Create database with all common options specified
CREATE DATABASE shop_prod
    WITH OWNER = devuser
    ENCODING = 'UTF8'
    LC_COLLATE = 'en_US.utf8'
    LC_CTYPE = 'en_US.utf8'
    CONNECTION LIMIT = 100;

Output:

TEXT
CREATE TABLE
⚠️ Note: CREATE DATABASE cannot be run inside a transaction (running it inside BEGIN...COMMIT errors out). This is by PG design — creating a database is a DDL operation and cannot be rolled back.


5. Template Databases

(1) template0 vs template1

PostgreSQL ships with two built-in template databases:

Property template0 template1
Purpose Pristine template, not modifiable Customizable template, modifiable
Modifiable? ❌ No ✅ Yes
Default contents Minimal system objects Same as template0 + user-defined objects
When to use When you need to restore original encoding/collation Daily database creation (default)
Creation TEMPLATE = template0 TEMPLATE = template1 (default)
📌 Key point: Once you create tables, functions, or extensions in template1, all new databases inherit those objects. This is a convenient way to pre-configure new databases.

▶ Example: Pre-Configure a Database with Templates

SQL
-- Step 1: Connect to template1 and add common extensions
\c template1

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";

-- Step 2: Now all new databases will have these extensions
\c postgres

CREATE DATABASE new_project;
-- new_project automatically has uuid-ossp and pg_trgm

-- Step 3: Verify
\c new_project
\dx

Output:

TEXT
CREATE TABLE

▶ Example: Rebuild Encoding with template0

SQL
-- If template1 has a different encoding than you need,
-- use template0 to create a database with specific encoding
CREATE DATABASE db_with_latin
    TEMPLATE = template0
    ENCODING = 'LATIN1'
    LC_COLLATE = 'C'
    LC_CTYPE = 'C';

Output:

TEXT
CREATE TABLE

6. ALTER DATABASE

(1) Common Modifications

Operation Syntax Description
Rename ALTER DATABASE old_name RENAME TO new_name Change the database name
Set parameter ALTER DATABASE name SET parameter = value Set a runtime parameter for the database
Reset parameter ALTER DATABASE name RESET parameter Restore the parameter's default
Change owner ALTER DATABASE name OWNER TO new_owner Change the database owner
Set connection limit ALTER DATABASE name CONNECTION LIMIT = n Change the max connection count
Mark as template ALTER DATABASE name IS_TEMPLATE = true Mark / unmark as a template

▶ Example: Modify Database Properties

SQL
-- Rename a database (must disconnect all users first)
ALTER DATABASE shop_dev RENAME TO shop_development;

-- Set default search_path for a database
ALTER DATABASE shop_prod SET search_path TO public, admin;

-- Set work_mem for a specific database
ALTER DATABASE shop_prod SET work_mem = '64MB';

-- Change connection limit
ALTER DATABASE shop_prod CONNECTION LIMIT = 200;

-- Mark as template
ALTER DATABASE shop_base IS_TEMPLATE = true;

Output:

TEXT
-- SQL statement executed successfully
⚠️ Note: Before renaming a database, you must disconnect all users connected to it. Use the following query to see active connections:

SQL
-- Find active connections to a database
SELECT pid, usename, application_name, client_addr, state
FROM pg_stat_activity
WHERE datname = 'shop_dev';

7. DROP DATABASE

(1) Drop Syntax

SQL
DROP DATABASE [IF EXISTS] name [WITH (FORCE)];
Option Description
IF EXISTS No error if the database doesn't exist (only a notice)
WITH (FORCE) Force-disconnect all connections, then drop (PG 13+)

▶ Example: Drop a Database

SQL
-- Safe delete (no error if database doesn't exist)
DROP DATABASE IF EXISTS old_project;

-- Force delete (disconnect all users first, PG 13+)
DROP DATABASE IF EXISTS shop_dev WITH (FORCE);

Output:

TEXT
-- SQL statement executed successfully
🔥 Gotcha: Dropping a database is irreversible! All tables, data, and views in the database are permanently lost. In production, always back up before dropping.


8. Character Set and Collation

(1) Common Character Encodings

Encoding Description Recommended scenario
UTF8 Unicode, supports all languages All projects (recommended)
LATIN1 Western European languages Legacy system compatibility
EUC_JP Japanese Legacy Japanese systems
SQL_ASCII No encoding conversion Pure ASCII data

(2) Collation Comparison

Collation Behavior Example
en_US.utf8 English sort, case-sensitive A, a, B, b
C Byte-order sort, fastest A, B, a, b
en_US.utf8 (with ICU) More flexible sorting Can ignore case/accents

▶ Example: View Encodings and Collations Supported by the System

SQL
-- List available encodings
SELECT name, description FROM pg_encodings LIMIT 10;

-- List available collations
SELECT name, locale FROM pg_collation LIMIT 10;

Output:

TEXT
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

▶ Example: How Collation Affects Query Results

SQL
-- Create a test table with text data
CREATE TABLE sort_test (name TEXT);
INSERT INTO sort_test VALUES ('apple'), ('Banana'), ('cherry'), ('Apple');

-- Sort with C locale (byte order: uppercase first)
SELECT name FROM sort_test ORDER BY name COLLATE "C";

-- Sort with en_US.utf8 (dictionary order: case-insensitive within same letter)
SELECT name FROM sort_test ORDER BY name COLLATE "en_US.utf8";

-- Clean up
DROP TABLE sort_test;

Output:

TEXT
-- C locale:
  Apple
  Banana
  apple
  cherry

-- en_US.utf8:
  apple
  Apple
  Banana
  cherry

9. psql Database Management Meta-Commands

Command Equivalent SQL Description
\l SELECT * FROM pg_database List all databases
\l+ Same, with tablespace/size List databases in detail
\c dbname - Switch to the specified database
\conninfo - Show current connection info

▶ Example: Manage Databases in psql

BASH
# List all databases
\l

# Switch to shop_dev database
\c shop_dev

# Check current connection
\conninfo

# Switch back to postgres database
\c postgres

Output:

TEXT
# command executed successfully

10. Complete Example: Three-Environment Database Setup

SQL
-- ============================================
-- Complete example: set up dev/staging/prod databases
-- For an e-commerce project
-- ============================================

-- Step 1: Connect to postgres (maintenance database)
\c postgres

-- Step 2: Create dev database with English locale
CREATE DATABASE shop_dev
    WITH ENCODING = 'UTF8'
    LC_COLLATE = 'en_US.utf8'
    LC_CTYPE = 'en_US.utf8'
    OWNER = devuser
    CONNECTION LIMIT = 50;

-- Step 3: Create staging database (same config as prod)
CREATE DATABASE shop_staging
    WITH ENCODING = 'UTF8'
    LC_COLLATE = 'en_US.utf8'
    LC_CTYPE = 'en_US.utf8'
    OWNER = devuser
    CONNECTION LIMIT = 50;

-- Step 4: Create prod database with connection limit
CREATE DATABASE shop_prod
    WITH ENCODING = 'UTF8'
    LC_COLLATE = 'en_US.utf8'
    LC_CTYPE = 'en_US.utf8'
    OWNER = devuser
    CONNECTION LIMIT = 200;

-- Step 5: Set default search_path for prod
ALTER DATABASE shop_prod SET search_path TO public, admin;

-- Step 6: Verify all databases created
SELECT datname, pg_encoding_to_char(encoding) AS encoding,
       datcollate, datctype, datconnlimit
FROM pg_database
WHERE datname LIKE 'shop_%'
ORDER BY datname;

Output:

TEXT
   datname    | encoding |  datcollate  |   datctype   | datconnlimit
--------------+----------+--------------+--------------+-------------
 shop_dev     | UTF8     | en_US.utf8   | en_US.utf8   |           50
 shop_prod    | UTF8     | en_US.utf8   | en_US.utf8   |          200
 shop_staging | UTF8     | en_US.utf8   | en_US.utf8   |           50

❓ FAQ

Q What is the maximum number of databases a PostgreSQL instance can create?
A There is no hard limit in theory, but each database consumes some system-catalog space. In practice, keep a single instance under 100 databases. If you need more isolation, consider using schemas instead.
Q What if CREATE DATABASE errors with "source database is being accessed by other users"?
A That means template1 is being used by another connection. Fix it by: 1) terminating all sessions connected to template1; or 2) using TEMPLATE = template0 instead.
Q What is the difference between LC_COLLATE and LC_CTYPE?
A LC_COLLATE controls the string sort order (the result of ORDER BY); LC_CTYPE controls character classification (case conversion, what counts as a letter, etc.). In most cases setting them the same is fine.
Q Can the character encoding be changed after the database is created?
A Not directly. You must pg_dump the data, create a new database with the new encoding, then pg_restore it. This is why UTF8 is recommended from the start — it supports every language.
Q How do I check the size of the current database?
A Use SELECT pg_size_pretty(pg_database_size('shop_dev')) for a single database, or \l+ to see all database sizes.
Q Can dev and prod share one database?
A Strongly not recommended. Operations during development (DROP TABLE, bulk DELETE) could accidentally destroy production data. Minimum requirement: dev and prod use different databases, preferably different PG instances.

📖 Summary


📝 Exercises

  1. Basic (★): Create a database named my_bookstore using UTF8 encoding, then verify with \l that it was created, and finally drop it.

  2. Intermediate (★★): First install the uuid-ossp extension in template1, then create a new database test_template and verify that the new database has automatically inherited the uuid-ossp extension.

  3. Challenge (★★★): Create two databases using the C and en_US.utf8 collations respectively. In each, create the same table and insert the data 'apple', 'Banana', 'cherry', 'Apple', then use ORDER BY to compare the sorting results and explain why they differ.

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏