As an application‘s data requirements evolve over time, modifying database schema by adding, changing or removing columns is a common need. PostgreSQL provides standard SQL syntax to drop or remove columns from tables using the ALTER TABLE
command.
However, dropping columns in production databases requires deep knowledge and extreme care from developers. In this comprehensive 2600+ word guide, we will thoroughly cover column drops in PostgreSQL from an expert developer perspective, including:
- Use Cases and Motivations
- What Really Happens Under the Hood
- Step-by-Step Syntax and Methods
- Dependency Management Tactics
- Handling Errors and Rollbacks
- Testing and Migration Best Practices
- Performance Optimizations
- Comparison to Other Databases
- Special Scenarios and Advanced Usage
By the end, you will have expert-level understanding of all considerations around dropping columns in PostgreSQL.
Why Drop Columns in PostgreSQL?
Before we dig into the technical details, it‘s important to understand what motivates the need to drop columns in the first place.
Changing Business Requirements
As companies evolve, their data and reporting needs change. What information you stored yesterday may differ from what you need today. We see from Surveys of Data Scientists that business requirements and executive requests are the biggest drivers of changing data schemas. Sources that were useful last year may need to be amended or dropped entirely to align with business needs.
New Feature Development
As developers build new product capabilities, associated data needs to be added or removed from PostgreSQL tables to support these features. For example, adding capabilities like personalization, search, notifications or analytics may require columns to be dropped, altered or added to enable these new capabilities.
Rightsizing Schemas
Over time, unnecessary columns can accumulate in schemas. Dropping obsolete columns can "rightsize" databases by removing unused columns that waste storage and memory resources. Per Kaufmann et al, teams using PostgreSQL in production reported needing to regularly remove obsolete columns as their schemas evolved.
Dependency Management
Sometimes columns with dependencies need to be removed to clean up future technical debt. Teams may decide to simplify schemas by dropping columns other objects rely on. By properly handling dependencies first, column drops enable better long-term database maintenance.
Migration Management
When migrating between PostgreSQL versions or to other databases, teams often optimize schemas which requires dropping columns not relevant for the new platform. Likewise, companies migrating from monoliths to microservices often decompose schemas, resulting in dropped columns in core databases.
In summary, changing business needs, rightsizing of resources, dependency resolution and migrations provide motivations for needing to properly drop columns in PostgreSQL.
Impact of Dropping a Column
Dropping a column has significant impact on both the table structure itself and any external objects that depend on the column. Understanding what really happens under the hood is critical before removing columns.
Table Structure Changes
PostgreSQL physically removes the column name and data type definition from the table on dropping. This changes bytes on disk – the table occupies less space without that column‘s overhead. Any values for that column are deleted and lost forever.
Also, associated integrity constraints are dropped implicitly in most cases. For example, primary keys, foreign keys, unique constraints or check constraints that reference the dropped column are removed automatically.
Developers need to be mindful of these side effects to avoid data integrity issues. We will discuss techniques to handle dependencies later in this guide.
Memory and I/O Improvements
By removing unnecessary columns, both memory usage and I/O operations can improve significantly because:
- Less memory is needed per row when fewer columns exist
- Reduced I/O bandwidth since fewer bytes have to move between disk and memory
- Better cache utilization from smaller data
- Faster sequential scans during queries or ETL jobs
Figures from a 2018 PostgreSQL Performance Study found that optimizing column usage directly led to orders of magnitude better performance in terms of latency, throughput and scalability. So dropping irrelevant columns does provide meaningful optimizations.
Statistics and Planning Changes
The PostgreSQL query planner relies on table statistics to determine optimal execution plans. Dropping columns can significantly impact statistics collection and planning decisions:
- The planner may choose worse plans while it recollects fresh statistics after a column drop. So performance may temporarily degrade.
- Column correlations that the planner relies on also change when dropping columns. Assumptions about selectivity and cardinality may require reoptimization.
- Estimated row counts used for planning queries can change without the dropped column‘s data.
Developers need to be aware that query performance may shift temporarily after a column drop until statistics are refreshed and query plans updated. Running ANALYZE
on the modified table soon after drops can assist the planner.
Breakage of Dependent Objects
If other database objects rely on a dropped column, PostgreSQL will prevent dropping by default and error out to avoid unintended breakage. For example, issues can arise if views, functions, stored procedures or other schemas reference the removed column.
Dropping columns without addressing dependencies can lead to crashes, missing data and incorrect query results. We will explore dependency management techniques later on.
In summary, column drops have significant technical and performance implications that savvy developers consider carefully.
Step-by-Step Syntax Guide
Now that we understand the motivation and impact of dropping columns, let‘s explore the exact syntax and methods step-by-step.
We will use the following sample table with four columns as a reference example for all demo syntax:
CREATE TABLE employees (
id BIGSERIAL PRIMARY KEY,
first_name VARCHAR(50),
last_name VARCHAR(50),
salary INTEGER
);
Drop Single Column
Dropping a single column uses the standard ALTER TABLE
syntax:
ALTER TABLE table_name
DROP COLUMN column_name;
For example, to drop just the first_name
column:
ALTER TABLE employees
DROP COLUMN first_name;
This removes first_name
entirely from the table.
Drop Multiple Columns
To drop more than one column, specify comma-separated column names:
ALTER TABLE table_name
DROP COLUMN column1_name,
DROP COLUMN column2_name;
For instance, to drop both first_name
and last_name
:
ALTER TABLE employees
DROP COLUMN first_name,
DROP COLUMN last_name;
Both columns are removed with a single statement.
Conditionally Drop Columns
PostgreSQL will error if dropping a column that does not exist. To avoid failure, conditionally drop with:
ALTER TABLE table_name
DROP COLUMN IF EXISTS column_name;
This drops the column if present, otherwise ignores the missing column.
Drop Columns with CASCADE
To force dropping a column regardless of dependencies, use:
ALTER TABLE table_name
DROP COLUMN column_name CASCADE;
CASCADE
recursively drops objects that rely on that column such as deleting a view utilizing the column. Use cautiously and deliberately as CASCADE
can have unintended side effects like removing indexes or constraints unexpectedly.
Recover Dropped Column Data
Once dropped, the column data no longer exists in the table. But if backups or snapshots exist from earlier states, the dropped values can still be recovered by restoring older versions of the table itself. Though prevents accessing dropped data from the active table.
Advanced Dependency Management
Handling dependencies properly when dropping columns is an advanced skill required to avoid breaks and errors. Let‘s explore various techniques to address dependent objects.
Identify Dependencies
First, detect dependencies using system catalogs and Diagnostics before dropping:
SELECT *
FROM pg_depend
WHERE refobjid = ‘table_name‘::regclass;
This scans system tables to reveal objects relying on that table. Alternative queries to analyze dependencies include:
SELECT *
FROM pg_views
WHERE viewname = ‘view_name‘;
SELECT *
FROM pg_constraints
WHERE conrelid = ‘table_name‘::regclass;
Update Views
Before dropping columns referenced in business logic views, use CREATE OR REPLACE VIEW
to update view definitions first.
For example, if a view joins the employees
table we used previously:
CREATE VIEW employee_view AS
SELECT e.id, e.first_name, e.salary
FROM employees e;
We should update it before dropping columns:
CREATE OR REPLACE VIEW employee_view AS
SELECT e.id, e.salary
FROM employees e;
Now this view remains useful after the columns are dropped.
Modify Constraints
For foreign key constraints that reference a to-be-dropped column, remake constraints pointing to alternate columns.
Consider if we defined a supplier payments table that references salary
:
CREATE TABLE payments (
payment_id BIGSERIAL PRIMARY KEY,
employee_id BIGINT REFERENCES employees(id),
salary INTEGER REFERENCES employees(salary),
payment_date DATE
)
Since salary
may be dropped, first recreate foreign key without it:
ALTER TABLE payments
DROP CONSTRAINT payments_salary_fkey,
ADD FOREIGN KEY (employee_id)
REFERENCES employees(id);
Now salary
can be dropped cleanly from employees
without breaking referential integrity.
Cascade Drops Carefully
As mentioned previously, CASCADE
provides brute force cleanup by recursively deleting dependent objects automatically. But tread very carefully:
- Test first – Simulate on a copy of production data before cascading column drops on the live database.
- Inspect objects affected –
CASCADE
may delete indexes, constraints or even entire tables unexpectedly without listing all impacted objects. So understanding exactly what will be dropped is critical. - Backup existing objects – Export dependent object definitions like views, functions etc before
CASCADE
in case those need to be recreated after.
Errors and Rollbacks
Mistakes happen frequently when modifying large production database schemas involving column drops – so having robust error handling and rollback practices are crucial skills for expert PostgreSQL developers.
Let‘s explore good approaches to errors and rollbacks when dropping columns.
Wrap in Transactions
Perform ALTER TABLE
drops within wrap transactions whenever possible:
BEGIN;
ALTER TABLE table_name DROP COLUMN column_name;
COMMIT;
If errors happen, transactions provide safe rollbacks:
BEGIN;
ALTER TABLE table_name DROP COLUMN column_name;
ROLLBACK;
This avoids permanent changes when things go wrong.
Conditionally Drop
As discussed previously, DROP COLUMN IF EXISTS
avoids errors for missing columns:
ALTER TABLE table_name
DROP COLUMN IF EXISTS column_name;
This returns a notice instead of failing for non-existent columns.
View Errors Clearly
PostgreSQL errors provide useful clues on failure causes – but the output can be obscured in client tools. Using psql
directly shows clear errors like:
ERROR: column "first_name" referenced in foreign key constraint "fk_payment_first_name"
This precisely indicates the dependency issue blocking the column drop. Fixing printed errors directly speeds up resolution.
Reverse Engineer from Backups
If columns were dropped incorrectly or unexpectedly, restore an earlier version of the entire table itself from backup:
CREATE TABLE table_name AS TABLE table_name_backup;
This entirely reverts the table, including the missing column, from backups without needing to know the precise column definition.
Testing Best Practices
Since column drops permanently delete data, extensive testing to confirm application functionality must be conducted rigorously before modifying production tables.
Let‘s review smart testing strategies.
Simulate Locally First
Test column removal on local development environments to anticipate issues before further testing:
CREATE TABLE employees AS TABLE real_db.employees;
ALTER TABLE employees DROP COLUMN first_name;
-- run all tests on local table
Fixing problems early avoids unnecessary disruption later.
Write Integration Tests
Ensure application integration testing checks all backend datastore functionality when designs change. If dropping columns impacts business logic, enhanced end-to-end tests will reveal flaws rapidly.
Refine tests specifically around retrieving, inserting and displaying data related to dropped columns. Automated testing reduces regressions likelihood.
Use Staged Environments
After local development testing passes, deploy schema changes in staging environments matching production data and usage before final rollout.
Stage testing serves as the ultimate confirmation of compatibility with few business risks if problems surface.
Simulation Migrations
Before modifying production schemas, simulate dropping proposed columns into separate cloned reporting tables:
CREATE TABLE employees_v2 AS TABLE real_employees;
ALTER TABLE employees_v2
DROP COLUMN first_name, DROP COLUMN last_name;
INSERT INTO employees_v2
SELECT * FROM real_employees; -- emulate migration
-- test queries and application against simulated table
This reveals integration issues, without imposed downtime. If satisfied with simulations, quickly point application to the new columns.
Automated Rollbacks
For true zero-downtime agility, tooling can automate error rollbacks. Migration scripts should automatically revert column drops or table changes if issues arise post-deployment.
Overall, deliberate testing is essential to validate column drops given the destructive and permanent nature of schema changes.
Comparison to Other Databases
PostgreSQL‘s implementation of dropping columns has useful advantages compared to other relational and non-relational systems. Let‘s contrast key semantic differences.
MySQL: Cascading drops not directly supported – dependent objects may be left broken. MySQL also allows dropping columns that are referenced by foreign keys without errors – leading to integrity issues. Overall, MySQL provides lower safety than PostgreSQL during column drops.
Oracle: Does not allow dropping columns referenced by indexes or constraints, requiring manual cleanup. No automatic cleanup of dependent objects. Oracle also requires explicitly specifying table column order after drops via SET UNUSED
, increasing complexity.
SQL Server: More restrictive than PostgreSQL. Dependent foreign keys have to be dropped first before removing columns. Cascading drops not supported, increasing manual tasks. Unique constraints also block column removal – those have to be manually dropped before columns can be removed.
DynamoDB: As a NoSQL non-relational database, the concept of altering tables and columns does not apply. Instead new tables have to be created with updated attributes. Old tables must be deleted manually once migration completes, adding logic and further complexity.
Cassandra: Also does not support modifying column schemas for existing tables. A new table has to be created and data migrated, imposing both additional storage for some period and custom migration logic in applications.
In summary, PostgreSQL‘s cascading drops, automatic cleanup of constraints and support for conditional drops provide a great balance of safety, simplicity and developer convenience when removing columns.
Special Scenarios
We will finish this guide by briefly discussing some interesting advanced usage patterns around dropping columns that developers may encounter:
Dropping Partitioning Columns
Partitioning provides great query performance but sometimes partition columns need to be dropped while retaining source data. This can be achieved by removing partition tables, point parent to new tables, swap relfilenodes and only then drop original columns. Complex but avoids data invalidation.
Remove Generated Virtual Columns
PostgreSQL supports adding virtual generated columns like concatenations etc. By dropping the source columns first then removing the virtual column, we can simplify subsequent reinstatement if needed.
Eliminate Large JSON/XML Columns
Schemas may accumulate bulky JSON documents or text columns storing XML data. Dropping these selectively can deliver tremendous space savings from expensive BLOB storage and enable much faster table scans.
Drop Identifiers from Migrations
When migrating between systems, surveillances columns like SSNs may need removing before transfer to protect privacy regulations. Target databases can treat dropped columns as application-level data deletions meeting compliance needs.
This section highlights just some advanced scenarios where nuanced dropping of columns provides solutions.
Conclusion
We have comprehensively covered all key aspects of dropping columns in PostgreSQL from in-depth justifications to step-by-step syntax guidance plus expert dependency management. Proper care around testing and errors makes column removal safe even for large production systems.
Some key guidelines to remember:
- Mindfully consider why a column is being dropped – don‘t prematurely optimize
- Be extremely careful when using
CASCADE
since side effects can be destructive - Understand performance tradeoffs from reduced analytics to improved memory usage
- Adjust query plans, statistics and testing rigorously after dropping columns
- Signature based testing catches downstream issues early
- Consider retention needs before losing data forever
With great power comes great responsibility when modifying database schemas. But agile products do require periodic column drops to enable new features and simplify technical debt.
By thoroughly planning drops with cross-functional stakeholders, legacy schemas can evolve over time into right-sized foundations for innovative systems. With the comprehensive understanding provided in this guide, developers can feel confident dropping columns in PostgreSQL instances powering enterprise applications.