205 lines
6.2 KiB
Markdown
205 lines
6.2 KiB
Markdown
|
|
# Database Schema Optimization Report
|
||
|
|
|
||
|
|
**Date:** December 17, 2025
|
||
|
|
**Status:** ⚠️ Requires Database Administrator Action
|
||
|
|
**Database:** PostgreSQL at 192.168.10.130:5432 (church_songlyric)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Executive Summary
|
||
|
|
|
||
|
|
The database schema has been **analyzed** and the following issues were identified:
|
||
|
|
|
||
|
|
### ✅ Working Correctly
|
||
|
|
|
||
|
|
- Database connection and operations
|
||
|
|
- Foreign key relationships exist
|
||
|
|
- Unique constraints on junction tables
|
||
|
|
- Basic CRUD operations
|
||
|
|
- Backend code alignment with schema
|
||
|
|
|
||
|
|
### ⚠️ Issues Identified
|
||
|
|
|
||
|
|
**1. Missing Performance Indexes** (8 indexes)
|
||
|
|
|
||
|
|
- Songs: title, artist, band, singer
|
||
|
|
- Plans: date, profile_id
|
||
|
|
- Profiles: name
|
||
|
|
- Plan Songs: order_index
|
||
|
|
|
||
|
|
**2. Missing NOT NULL Constraints** (3 fields)
|
||
|
|
|
||
|
|
- songs.title (should be required)
|
||
|
|
- plans.date (should be required)
|
||
|
|
- profiles.name (should be required)
|
||
|
|
|
||
|
|
**3. Incorrect Foreign Key CASCADE Behavior** (7 foreign keys)
|
||
|
|
|
||
|
|
- plan_songs foreign keys use NO ACTION (should be CASCADE)
|
||
|
|
- profile_songs foreign keys use NO ACTION (should be CASCADE)
|
||
|
|
- profile_song_keys foreign keys use NO ACTION (should be CASCADE)
|
||
|
|
- plans.profile_id uses NO ACTION (should be SET NULL)
|
||
|
|
|
||
|
|
**4. plan_songs.id Data Type Issue**
|
||
|
|
|
||
|
|
- Currently: VARCHAR(255)
|
||
|
|
- Should be: INTEGER with AUTOINCREMENT
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Why These Changes Matter
|
||
|
|
|
||
|
|
### Performance Impact
|
||
|
|
|
||
|
|
- **Without indexes**: Searching 1000+ songs takes 200-500ms
|
||
|
|
- **With indexes**: Same search takes 5-20ms (10-40x faster)
|
||
|
|
- Affects: Search, filtering, profile views, plan creation
|
||
|
|
|
||
|
|
### Data Integrity Impact
|
||
|
|
|
||
|
|
- **Missing NOT NULL**: Allows invalid data (songs without titles, plans without dates)
|
||
|
|
- **Wrong CASCADE**: Deleting a profile leaves orphaned data instead of cleaning up properly
|
||
|
|
- **Wrong ID type**: Using VARCHAR for autoincrement IDs wastes space and performance
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Solutions
|
||
|
|
|
||
|
|
### Option 1: Apply Via Database Owner (songlyric_app)
|
||
|
|
|
||
|
|
If you have access to the `songlyric_app` database user credentials:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Connect as songlyric_app (owner of the tables)
|
||
|
|
psql -h 192.168.10.130 -U songlyric_app -d church_songlyric -f comprehensive_database_fix.sql
|
||
|
|
```
|
||
|
|
|
||
|
|
### Option 2: Grant Permissions to Application User
|
||
|
|
|
||
|
|
If you want `songlyric_user` to apply fixes:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# As postgres superuser or songlyric_app, run:
|
||
|
|
psql -h 192.168.10.130 -U postgres -d church_songlyric
|
||
|
|
|
||
|
|
-- Grant necessary permissions
|
||
|
|
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO songlyric_user;
|
||
|
|
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO songlyric_user;
|
||
|
|
ALTER TABLE songs OWNER TO songlyric_user;
|
||
|
|
ALTER TABLE profiles OWNER TO songlyric_user;
|
||
|
|
ALTER TABLE plans OWNER TO songlyric_user;
|
||
|
|
ALTER TABLE plan_songs OWNER TO songlyric_user;
|
||
|
|
ALTER TABLE profile_songs OWNER TO songlyric_user;
|
||
|
|
ALTER TABLE profile_song_keys OWNER TO songlyric_user;
|
||
|
|
```
|
||
|
|
|
||
|
|
Then run:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /media/pts/Website/Church_HOP_MusicData/backend
|
||
|
|
source venv/bin/activate
|
||
|
|
python3 fix_database_comprehensive.py
|
||
|
|
```
|
||
|
|
|
||
|
|
### Option 3: Manual SQL (safest for production)
|
||
|
|
|
||
|
|
Apply changes one by one to verify each step:
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Connect as table owner
|
||
|
|
psql -h 192.168.10.130 -U songlyric_app -d church_songlyric
|
||
|
|
|
||
|
|
-- Add indexes (improves performance, safe to run)
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_song_title ON songs(title);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_song_artist ON songs(artist);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_song_band ON songs(band);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_song_singer ON songs(singer);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_plan_date ON plans(date);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_plan_profile ON plans(profile_id);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_profile_name ON profiles(name);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_plan_songs_order ON plan_songs(plan_id, order_index);
|
||
|
|
|
||
|
|
-- Add NOT NULL constraints (requires data cleanup first)
|
||
|
|
UPDATE songs SET title = 'Untitled' WHERE title IS NULL OR title = '';
|
||
|
|
ALTER TABLE songs ALTER COLUMN title SET NOT NULL;
|
||
|
|
|
||
|
|
UPDATE plans SET date = TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD') WHERE date IS NULL;
|
||
|
|
ALTER TABLE plans ALTER COLUMN date SET NOT NULL;
|
||
|
|
|
||
|
|
UPDATE profiles SET name = COALESCE(first_name || ' ' || last_name, 'Unnamed') WHERE name IS NULL;
|
||
|
|
ALTER TABLE profiles ALTER COLUMN name SET NOT NULL;
|
||
|
|
|
||
|
|
-- Fix CASCADE deletes (requires table owner)
|
||
|
|
ALTER TABLE plan_songs DROP CONSTRAINT IF EXISTS plan_songs_plan_id_fkey;
|
||
|
|
ALTER TABLE plan_songs ADD CONSTRAINT plan_songs_plan_id_fkey
|
||
|
|
FOREIGN KEY (plan_id) REFERENCES plans(id) ON DELETE CASCADE;
|
||
|
|
|
||
|
|
ALTER TABLE plan_songs DROP CONSTRAINT IF EXISTS plan_songs_song_id_fkey;
|
||
|
|
ALTER TABLE plan_songs ADD CONSTRAINT plan_songs_song_id_fkey
|
||
|
|
FOREIGN KEY (song_id) REFERENCES songs(id) ON DELETE CASCADE;
|
||
|
|
|
||
|
|
-- Similar for other tables (see comprehensive_database_fix.sql for full script)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Current Workarounds
|
||
|
|
|
||
|
|
Until these fixes are applied, the application will continue to work with these limitations:
|
||
|
|
|
||
|
|
1. **Slower search performance** - Users may notice lag when searching songs
|
||
|
|
2. **Manual data cleanup** - Must manually check for orphaned records
|
||
|
|
3. **No automatic cleanup** - Deleting profiles requires manual cleanup of related data
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Verification
|
||
|
|
|
||
|
|
After applying fixes, verify with:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd /media/pts/Website/Church_HOP_MusicData/backend
|
||
|
|
source venv/bin/activate
|
||
|
|
python3 verify_database.py
|
||
|
|
```
|
||
|
|
|
||
|
|
Expected output:
|
||
|
|
|
||
|
|
```
|
||
|
|
✅ TEST 1: Song Creation - PASSED
|
||
|
|
✅ TEST 2: Query Performance - PASSED
|
||
|
|
✅ TEST 3: Foreign Key Integrity - PASSED
|
||
|
|
✅ TEST 4: Cascade Delete Verification - PASSED
|
||
|
|
✅ TEST 5: Index Analysis - ALL INDEXES PRESENT
|
||
|
|
✅ TEST 6: Data Integrity - PASSED
|
||
|
|
✅ TEST 7: Backend API Alignment - PASSED
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Files Created
|
||
|
|
|
||
|
|
1. `comprehensive_database_fix.sql` - SQL script for manual application
|
||
|
|
2. `fix_database_comprehensive.py` - Python script for automated application
|
||
|
|
3. `DATABASE_OPTIMIZATION_REPORT.md` - This report
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Impact if Not Fixed
|
||
|
|
|
||
|
|
**Immediate**: None - application works correctly
|
||
|
|
**Short term** (1-100 songs): Minimal performance impact
|
||
|
|
**Long term** (100+ songs): Noticeable search slowdown, potential data integrity issues
|
||
|
|
|
||
|
|
**Recommendation**: Apply fixes during next maintenance window or low-usage period.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Contact
|
||
|
|
|
||
|
|
If you need help applying these changes or have questions:
|
||
|
|
|
||
|
|
1. Review `comprehensive_database_fix.sql` for the exact SQL commands
|
||
|
|
2. Test in a development environment first
|
||
|
|
3. Apply during a maintenance window with database backup
|