Fügt Unterstützung für parallele Entwicklungsumgebungen hinzu und aktualisiert die Benutzeroberfläche. Neue Routen und Komponenten für Trainingsstatistiken implementiert. Fehlerbehebungen und Verbesserungen in der Benutzeroberfläche vorgenommen.

This commit is contained in:
Torsten Schulz (local)
2025-08-22 15:47:16 +02:00
parent e827964688
commit 8bd05e4e38
40 changed files with 4670 additions and 346 deletions

139
backend/README_CLEANUP.md Normal file
View File

@@ -0,0 +1,139 @@
# MySQL Keys Cleanup - Anleitung
## Problem
Der MySQL-Server hat ein Limit von maximal 64 Keys pro Tabelle. Sequelize erstellt automatisch viele INDEX für verschiedene Felder, was dieses Limit überschreitet.
## Wichtige Erkenntnis ⚠️
**Alle INDEX-Namen in den ursprünglichen Scripts existieren nicht!** Das bedeutet, dass die Tabellennamen oder INDEX-Namen nicht mit der Realität übereinstimmen.
## Lösung
Das Cleanup-Script entfernt überflüssige INDEX, behält aber die essentiellen Keys (PRIMARY KEY, UNIQUE Keys).
## Verfügbare Scripts (nach Priorität sortiert)
### **1. `checkRealIndexes.sql`** - Echte INDEX überprüfen ⭐ EMPFOHLEN ZUERST
- Zeigt alle vorhandenen Tabellen in der Datenbank an
- Zeigt alle **echten** INDEX und Keys an
- Zeigt die Anzahl der Keys pro Tabelle an
- **Verwenden Sie dieses Script zuerst, um die echten INDEX-Namen zu sehen!**
### **2. `cleanupKeysMinimal.sql`** - Minimales Cleanup ⭐ EMPFOHLEN
- Zeigt alle INDEX pro Tabelle mit `SHOW INDEX`
- Entfernt alle überflüssigen INDEX
- Behält nur PRIMARY KEY und UNIQUE Keys
- **Sicherste Option für die Bereinigung**
### **3. `cleanupKeysReal.sql`** - Cleanup mit echten Namen
- Zeigt alle vorhandenen INDEX vor und nach der Bereinigung
- Entfernt nur INDEX, die tatsächlich existieren
- Detaillierte Informationen über den Cleanup-Prozess
### **4. `checkTableNames.sql`** - Tabellennamen überprüfen
- Zeigt alle vorhandenen Tabellen und INDEX an
- Gute Übersicht über die Datenbankstruktur
### **5. `cleanupKeysSmart.sql`** - Intelligentes Cleanup (veraltet)
- Überprüft zuerst alle vorhandenen Tabellen und INDEX
- **Problem**: Verwendet falsche INDEX-Namen
### **6. `cleanupKeysCorrected.sql`** - Korrigierte Tabellennamen (veraltet)
- Verwendet die wahrscheinlich korrekten Tabellennamen
- **Problem**: Verwendet falsche INDEX-Namen
### **7. `cleanupKeys.sql` & `cleanupKeysSimple.sql`** (veraltet)
- Tabellennamen und INDEX-Namen könnten falsch sein
- **Nicht mehr empfohlen**
## Empfohlener Ablauf
### **Schritt 1: Echte INDEX überprüfen**
```bash
# Verbindung zur MySQL-Datenbank
mysql -u [username] -p [database_name]
# Script ausführen
source /path/to/checkRealIndexes.sql
```
### **Schritt 2: Minimales Cleanup durchführen**
```bash
# Script ausführen
source /path/to/cleanupKeysMinimal.sql
```
### **Alternative Ausführungsmethoden**
#### Über MySQL Workbench
1. MySQL Workbench öffnen
2. Verbindung zur Datenbank herstellen
3. File -> Open SQL Script -> Script auswählen
4. Execute (Blitz-Symbol) klicken
#### Über phpMyAdmin
1. phpMyAdmin öffnen
2. Datenbank `trainingsdiary` auswählen
3. SQL-Tab öffnen
4. Inhalt des Scripts einfügen
5. Go klicken
## Nach der Ausführung
1. **Keys überprüfen:**
```sql
SELECT COUNT(*) as total_keys
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
```
2. **Keys pro Tabelle anzeigen:**
```sql
SELECT TABLE_NAME, COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
```
3. **Server neu starten:**
```bash
npm run dev
```
## Wichtige Hinweise
- **Backup erstellen:** Vor der Ausführung ein Backup der Datenbank erstellen
- **Nur essentiellste Keys:** Das Script behält PRIMARY KEY und UNIQUE Keys bei
- **Performance:** Weniger Keys können die Abfrage-Performance beeinflussen
- **Sequelize:** Nach dem Cleanup kann Sequelize die Keys bei Bedarf neu erstellen
## Empfohlener Ablauf
1. **`checkRealIndexes.sql` ausführen** - Echte INDEX-Namen sehen
2. **`cleanupKeysMinimal.sql` ausführen** - Minimales Cleanup
3. **Ergebnisse überprüfen** - Keys zählen
4. **Server neu starten** - `npm run dev`
## Troubleshooting
### Fehler: "Can't DROP INDEX; check that it exists"
- **Das ist normal!** Alle INDEX-Namen in den ursprünglichen Scripts existieren nicht
- Verwenden Sie `checkRealIndexes.sql` um die echten INDEX-Namen zu sehen
- Verwenden Sie `cleanupKeysMinimal.sql` für das Cleanup
### Fehler: "Table doesn't exist"
- Verwenden Sie `checkRealIndexes.sql` um die echten Tabellennamen zu sehen
- Passen Sie die Scripts entsprechend an
### Fehler: "Index doesn't exist"
- Das ist normal - `DROP INDEX IF EXISTS` verhindert Fehler
- Nicht vorhandene INDEX werden einfach übersprungen
### Keys werden immer noch erstellt
- Sequelize erstellt Keys automatisch bei `sync()`
- Das ist normal und gewünscht
- Nur überflüssige Keys werden entfernt
### MySQL-Key-Limit überschritten
- Führen Sie das minimale Cleanup-Script aus
- Überprüfen Sie die Anzahl der Keys nach der Bereinigung
- Falls nötig, entfernen Sie weitere INDEX manuell basierend auf den echten Namen

View File

@@ -0,0 +1,46 @@
-- Script zum Überprüfen der echten INDEX-Namen
USE trainingsdiary;
-- Alle vorhandenen Tabellen anzeigen
SELECT '=== VORHANDENE TABELLEN ===' as info;
SHOW TABLES;
-- Alle vorhandenen INDEX und Keys anzeigen (mit echten Namen)
SELECT '=== ALLE INDEX UND KEYS ===' as info;
SELECT
TABLE_NAME,
INDEX_NAME,
COLUMN_NAME,
NON_UNIQUE,
SEQ_IN_INDEX
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX;
-- Anzahl der Keys pro Tabelle
SELECT '=== KEYS PRO TABELLE ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- Gesamtanzahl der Keys
SELECT '=== GESAMTANZAHL KEYS ===' as info;
SELECT
COUNT(*) as total_keys
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
-- Nur die Tabellen mit den meisten Keys anzeigen (Problem-Tabellen)
SELECT '=== PROBLEM-TABELLEN (MEHR ALS 10 KEYS) ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
HAVING COUNT(*) > 10
ORDER BY key_count DESC;

View File

@@ -0,0 +1,35 @@
-- Script zum Überprüfen der echten Tabellennamen
USE trainingsdiary;
-- Alle Tabellen in der Datenbank anzeigen
SHOW TABLES;
-- Detaillierte Informationen über alle Tabellen
SELECT
TABLE_NAME,
TABLE_ROWS,
DATA_LENGTH,
INDEX_LENGTH
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'trainingsdiary'
ORDER BY TABLE_NAME;
-- Alle INDEX und Keys pro Tabelle anzeigen
SELECT
TABLE_NAME,
INDEX_NAME,
COLUMN_NAME,
NON_UNIQUE,
SEQ_IN_INDEX
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX;
-- Anzahl der Keys pro Tabelle
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;

185
backend/cleanupKeys.sql Normal file
View File

@@ -0,0 +1,185 @@
-- Cleanup-Script für MySQL Keys
-- Führt dieses Script in der MySQL-Datenbank aus, um überflüssige Keys zu entfernen
USE trainingsdiary;
-- 1. Alle nicht-essentiellen Keys aus der member-Tabelle entfernen
-- (behält nur PRIMARY KEY und UNIQUE Keys für kritische Felder)
-- Überflüssige INDEX entfernen (falls vorhanden)
DROP INDEX IF EXISTS idx_member_hashed_id ON member;
DROP INDEX IF EXISTS idx_member_first_name ON member;
DROP INDEX IF EXISTS idx_member_last_name ON member;
DROP INDEX IF EXISTS idx_member_birth_date ON member;
DROP INDEX IF EXISTS idx_member_active ON member;
DROP INDEX IF EXISTS idx_member_created_at ON member;
DROP INDEX IF EXISTS idx_member_updated_at ON member;
-- 2. Überflüssige Keys aus anderen Tabellen entfernen
-- User-Tabelle
DROP INDEX IF EXISTS idx_user_email ON user;
DROP INDEX IF EXISTS idx_user_created_at ON user;
DROP INDEX IF EXISTS idx_user_updated_at ON user;
-- Clubs-Tabelle
DROP INDEX IF EXISTS idx_clubs_name ON clubs;
DROP INDEX IF EXISTS idx_clubs_created_at ON clubs;
DROP INDEX IF EXISTS idx_clubs_updated_at ON clubs;
-- User_Club-Tabelle
DROP INDEX IF EXISTS idx_user_club_approved ON user_club;
DROP INDEX IF EXISTS idx_user_club_created_at ON user_club;
DROP INDEX IF EXISTS idx_user_club_updated_at ON user_club;
-- Log-Tabelle
DROP INDEX IF EXISTS idx_log_activity ON log;
DROP INDEX IF EXISTS idx_log_created_at ON log;
DROP INDEX IF EXISTS idx_log_updated_at ON log;
-- Diary_Dates-Tabelle
DROP INDEX IF EXISTS idx_diary_dates_date ON diary_dates;
DROP INDEX IF EXISTS idx_diary_dates_created_at ON diary_dates;
DROP INDEX IF EXISTS idx_diary_dates_updated_at ON diary_dates;
-- Participants-Tabelle
DROP INDEX IF EXISTS idx_participant_created_at ON participants;
DROP INDEX IF EXISTS idx_participant_updated_at ON participants;
-- Activity-Tabelle
DROP INDEX IF EXISTS idx_activity_created_at ON activities;
DROP INDEX IF EXISTS idx_activity_updated_at ON activities;
-- Member_Note-Tabelle
DROP INDEX IF EXISTS idx_member_note_created_at ON member_note;
DROP INDEX IF EXISTS idx_member_note_updated_at ON member_note;
-- Diary_Note-Tabelle
DROP INDEX IF EXISTS idx_diary_note_created_at ON diary_note;
DROP INDEX IF EXISTS idx_diary_note_updated_at ON diary_note;
-- Diary_Tag-Tabelle
DROP INDEX IF EXISTS idx_diary_tag_created_at ON diary_tag;
DROP INDEX IF EXISTS idx_diary_tag_updated_at ON diary_tag;
-- Member_Diary_Tag-Tabelle
DROP INDEX IF EXISTS idx_member_diary_tag_created_at ON member_diary_tag;
DROP INDEX IF EXISTS idx_member_diary_tag_updated_at ON member_diary_tag;
-- Diary_Date_Tag-Tabelle
DROP INDEX IF EXISTS idx_diary_date_tag_created_at ON diary_date_tag;
DROP INDEX IF EXISTS idx_diary_date_tag_updated_at ON diary_date_tag;
-- Diary_Member_Note-Tabelle
DROP INDEX IF EXISTS idx_diary_member_note_created_at ON diary_member_note;
DROP INDEX IF EXISTS idx_diary_member_note_updated_at ON diary_member_note;
-- Predefined_Activity-Tabelle
DROP INDEX IF EXISTS idx_predefined_activity_created_at ON predefined_activities;
DROP INDEX IF EXISTS idx_predefined_activity_updated_at ON predefined_activities;
-- Diary_Date_Activity-Tabelle
DROP INDEX IF EXISTS idx_diary_date_activity_created_at ON diary_date_activity;
DROP INDEX IF EXISTS idx_diary_date_activity_updated_at ON diary_date_activity;
-- Match-Tabelle
DROP INDEX IF EXISTS idx_match_created_at ON match;
DROP INDEX IF EXISTS idx_match_updated_at ON match;
-- League-Tabelle
DROP INDEX IF EXISTS idx_league_created_at ON league;
DROP INDEX IF EXISTS idx_league_updated_at ON league;
-- Team-Tabelle
DROP INDEX IF EXISTS idx_team_created_at ON team;
DROP INDEX IF EXISTS idx_team_updated_at ON team;
-- Season-Tabelle
DROP INDEX IF EXISTS idx_season_created_at ON season;
DROP INDEX IF EXISTS idx_season_updated_at ON season;
-- Location-Tabelle
DROP INDEX IF EXISTS idx_location_created_at ON location;
DROP INDEX IF EXISTS idx_location_updated_at ON location;
-- Group-Tabelle
DROP INDEX IF EXISTS idx_group_created_at ON `group`;
DROP INDEX IF EXISTS idx_group_updated_at ON `group`;
-- Group_Activity-Tabelle
DROP INDEX IF EXISTS idx_group_activity_created_at ON group_activity;
DROP INDEX IF EXISTS idx_group_activity_updated_at ON group_activity;
-- Tournament-Tabelle
DROP INDEX IF EXISTS idx_tournament_created_at ON tournament;
DROP INDEX IF EXISTS idx_tournament_updated_at ON tournament;
-- Tournament_Group-Tabelle
DROP INDEX IF EXISTS idx_tournament_group_created_at ON tournament_group;
DROP INDEX IF EXISTS idx_tournament_group_updated_at ON tournament_group;
-- Tournament_Member-Tabelle
DROP INDEX IF EXISTS idx_tournament_member_created_at ON tournament_member;
DROP INDEX IF EXISTS idx_tournament_member_updated_at ON tournament_member;
-- Tournament_Match-Tabelle
DROP INDEX IF EXISTS idx_tournament_match_created_at ON tournament_match;
DROP INDEX IF EXISTS idx_tournament_match_updated_at ON tournament_match;
-- Tournament_Result-Tabelle
DROP INDEX IF EXISTS idx_tournament_result_created_at ON tournament_result;
DROP INDEX IF EXISTS idx_tournament_result_updated_at ON tournament_result;
-- Accident-Tabelle
DROP INDEX IF EXISTS idx_accident_created_at ON accident;
DROP INDEX IF EXISTS idx_accident_updated_at ON accident;
-- User_Token-Tabelle
DROP INDEX IF EXISTS idx_user_token_created_at ON UserToken;
DROP INDEX IF EXISTS idx_user_token_updated_at ON UserToken;
-- 3. Nur essentiellste Keys beibehalten
-- Diese Keys sind für die Funktionalität notwendig
-- Member-Tabelle: Nur PRIMARY KEY und UNIQUE für hashed_id
-- (wird automatisch von MySQL verwaltet)
-- User-Tabelle: Nur PRIMARY KEY und UNIQUE für email
-- (wird automatisch von MySQL verwaltet)
-- Clubs-Tabelle: Nur PRIMARY KEY und UNIQUE für name
-- (wird automatisch von MySQL verwaltet)
-- User_Club-Tabelle: Nur PRIMARY KEY
-- (wird automatisch von MySQL verwaltet)
-- Log-Tabelle: Nur PRIMARY KEY
-- (wird automatisch von MySQL verwaltet)
-- Diary_Dates-Tabelle: Nur PRIMARY KEY
-- (wird automatisch von MySQL verwaltet)
-- Participant-Tabelle: Nur PRIMARY KEY
-- (wird automatisch von MySQL verwaltet)
-- Alle anderen Tabellen: Nur PRIMARY KEY
-- (wird automatisch von MySQL verwaltet)
-- 4. Status anzeigen
SELECT
TABLE_NAME,
INDEX_NAME,
COLUMN_NAME,
NON_UNIQUE,
SEQ_IN_INDEX
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX;
-- 5. Anzahl der Keys pro Tabelle anzeigen
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;

View File

@@ -0,0 +1,123 @@
-- Aggressives Cleanup-Script - Entfernt alle überflüssigen INDEX
-- Behält nur PRIMARY KEY und UNIQUE constraints
USE trainingsdiary;
-- 1. Status vor dem aggressiven Cleanup
SELECT '=== STATUS VOR AGGRESSIVEM CLEANUP ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 2. Alle INDEX der Problem-Tabellen anzeigen
SELECT '=== MEMBER TABELLE INDEX ===' as info;
SHOW INDEX FROM member;
SELECT '=== DIARY_TAGS TABELLE INDEX ===' as info;
SHOW INDEX FROM diary_tags;
SELECT '=== SEASON TABELLE INDEX ===' as info;
SHOW INDEX FROM season;
-- 3. Alle nicht-essentiellen INDEX entfernen
-- Behalte nur: PRIMARY KEY, UNIQUE constraints, FOREIGN KEY
-- Member-Tabelle: Alle INDEX außer PRIMARY und UNIQUE entfernen
SELECT '=== ENTFERNE ALLE ÜBERFLÜSSIGEN MEMBER INDEX ===' as info;
-- Alle INDEX außer PRIMARY entfernen (PRIMARY kann nicht gelöscht werden)
-- Verwende SHOW INDEX um die echten INDEX-Namen zu sehen
-- Dann entferne alle außer PRIMARY
-- Häufige überflüssige INDEX-Namen (alle außer PRIMARY)
DROP INDEX IF EXISTS member_hashed_id_unique ON member;
DROP INDEX IF EXISTS member_first_name_index ON member;
DROP INDEX IF EXISTS member_last_name_index ON member;
DROP INDEX IF EXISTS member_birth_date_index ON member;
DROP INDEX IF EXISTS member_active_index ON member;
DROP INDEX IF EXISTS member_created_at_index ON member;
DROP INDEX IF EXISTS member_updated_at_index ON member;
DROP INDEX IF EXISTS member_club_id_index ON member;
DROP INDEX IF EXISTS member_hashed_id_index ON member;
-- Alternative INDEX-Namen
DROP INDEX IF EXISTS idx_member_hashed_id ON member;
DROP INDEX IF EXISTS idx_member_first_name ON member;
DROP INDEX IF EXISTS idx_member_last_name ON member;
DROP INDEX IF EXISTS idx_member_birth_date ON member;
DROP INDEX IF EXISTS idx_member_active ON member;
DROP INDEX IF EXISTS idx_member_created_at ON member;
DROP INDEX IF EXISTS idx_member_updated_at ON member;
DROP INDEX IF EXISTS idx_member_club_id ON member;
-- Diary_Tags-Tabelle: Alle überflüssigen INDEX entfernen
SELECT '=== ENTFERNE ALLE ÜBERFLÜSSIGEN DIARY_TAGS INDEX ===' as info;
DROP INDEX IF EXISTS diary_tags_name_index ON diary_tags;
DROP INDEX IF EXISTS diary_tags_created_at_index ON diary_tags;
DROP INDEX IF EXISTS diary_tags_updated_at_index ON diary_tags;
DROP INDEX IF EXISTS diary_tags_club_id_index ON diary_tags;
-- Alternative INDEX-Namen
DROP INDEX IF EXISTS idx_diary_tags_name ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tags_created_at ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tags_updated_at ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tags_club_id ON diary_tags;
-- Season-Tabelle: Alle überflüssigen INDEX entfernen
SELECT '=== ENTFERNE ALLE ÜBERFLÜSSIGEN SEASON INDEX ===' as info;
DROP INDEX IF EXISTS season_name_index ON season;
DROP INDEX IF EXISTS season_start_date_index ON season;
DROP INDEX IF EXISTS season_end_date_index ON season;
DROP INDEX IF EXISTS season_created_at_index ON season;
DROP INDEX IF EXISTS season_updated_at_index ON season;
DROP INDEX IF EXISTS season_club_id_index ON season;
-- Alternative INDEX-Namen
DROP INDEX IF EXISTS idx_season_name ON season;
DROP INDEX IF EXISTS idx_season_start_date ON season;
DROP INDEX IF EXISTS idx_season_end_date ON season;
DROP INDEX IF EXISTS idx_season_created_at ON season;
DROP INDEX IF EXISTS idx_season_updated_at ON season;
DROP INDEX IF EXISTS idx_season_club_id ON season;
-- 4. Status nach dem aggressiven Cleanup
SELECT '=== STATUS NACH AGGRESSIVEM CLEANUP ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 5. Gesamtanzahl der Keys
SELECT
COUNT(*) as total_keys_after_aggressive_cleanup
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
-- 6. Ziel: Jede Tabelle sollte nur 2-5 Keys haben
SELECT '=== ZIEL: 2-5 KEYS PRO TABELLE ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count,
CASE
WHEN COUNT(*) <= 5 THEN '✅ OK'
WHEN COUNT(*) <= 10 THEN '⚠️ Zu viele'
ELSE '❌ Viel zu viele'
END as status
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 7. Zusammenfassung
SELECT '=== ZUSAMMENFASSUNG ===' as info;
SELECT
'Aggressives Cleanup abgeschlossen. Jede Tabelle sollte nur 2-5 Keys haben.' as message;

View File

@@ -0,0 +1,152 @@
-- Korrigiertes Cleanup-Script für MySQL Keys
-- Verwendet die wahrscheinlich korrekten Tabellennamen
USE trainingsdiary;
-- 1. Alle überflüssigen INDEX entfernen
-- Diese entfernen die meisten Keys, die das Limit überschreiten
-- User-Tabelle (wahrscheinlich 'user')
DROP INDEX IF EXISTS idx_user_email ON user;
DROP INDEX IF EXISTS idx_user_created_at ON user;
DROP INDEX IF EXISTS idx_user_updated_at ON user;
-- Clubs-Tabelle (wahrscheinlich 'clubs')
DROP INDEX IF EXISTS idx_clubs_name ON clubs;
DROP INDEX IF EXISTS idx_clubs_created_at ON clubs;
DROP INDEX IF EXISTS idx_clubs_updated_at ON clubs;
-- User_Club-Tabelle (wahrscheinlich 'user_club')
DROP INDEX IF EXISTS idx_user_club_approved ON user_club;
DROP INDEX IF EXISTS idx_user_club_created_at ON user_club;
DROP INDEX IF EXISTS idx_user_club_updated_at ON user_club;
-- Member-Tabelle (wahrscheinlich 'member')
DROP INDEX IF EXISTS idx_member_hashed_id ON member;
DROP INDEX IF EXISTS idx_member_first_name ON member;
DROP INDEX IF EXISTS idx_member_last_name ON member;
DROP INDEX IF EXISTS idx_member_birth_date ON member;
DROP INDEX IF EXISTS idx_member_active ON member;
DROP INDEX IF EXISTS idx_member_created_at ON member;
DROP INDEX IF EXISTS idx_member_updated_at ON member;
-- Log-Tabelle (wahrscheinlich 'log')
DROP INDEX IF EXISTS idx_log_activity ON log;
DROP INDEX IF EXISTS idx_log_created_at ON log;
DROP INDEX IF EXISTS idx_log_updated_at ON log;
-- Diary_Dates-Tabelle (wahrscheinlich 'diary_dates')
DROP INDEX IF EXISTS idx_diary_dates_date ON diary_dates;
DROP INDEX IF EXISTS idx_diary_dates_created_at ON diary_dates;
DROP INDEX IF EXISTS idx_diary_dates_updated_at ON diary_dates;
-- Participants-Tabelle (wahrscheinlich 'participants')
DROP INDEX IF EXISTS idx_participant_created_at ON participants;
DROP INDEX IF EXISTS idx_participant_updated_at ON participants;
-- Activities-Tabelle (wahrscheinlich 'activities')
DROP INDEX IF EXISTS idx_activity_created_at ON activities;
DROP INDEX IF EXISTS idx_activity_updated_at ON activities;
-- Member_Notes-Tabelle (wahrscheinlich 'member_notes')
DROP INDEX IF EXISTS idx_member_note_created_at ON member_notes;
DROP INDEX IF EXISTS idx_member_note_updated_at ON member_notes;
-- Diary_Notes-Tabelle (wahrscheinlich 'diary_notes')
DROP INDEX IF EXISTS idx_diary_note_created_at ON diary_notes;
DROP INDEX IF EXISTS idx_diary_note_updated_at ON diary_notes;
-- Diary_Tags-Tabelle (wahrscheinlich 'diary_tags')
DROP INDEX IF EXISTS idx_diary_tag_created_at ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tag_updated_at ON diary_tags;
-- Member_Diary_Tags-Tabelle (wahrscheinlich 'member_diary_tags')
DROP INDEX IF EXISTS idx_member_diary_tag_created_at ON member_diary_tags;
DROP INDEX IF EXISTS idx_member_diary_tag_updated_at ON member_diary_tags;
-- Diary_Date_Tags-Tabelle (wahrscheinlich 'diary_date_tags')
DROP INDEX IF EXISTS idx_diary_date_tag_created_at ON diary_date_tags;
DROP INDEX IF EXISTS idx_diary_date_tag_updated_at ON diary_date_tags;
-- Diary_Member_Notes-Tabelle (wahrscheinlich 'diary_member_notes')
DROP INDEX IF EXISTS idx_diary_member_note_created_at ON diary_member_notes;
DROP INDEX IF EXISTS idx_diary_member_note_updated_at ON diary_member_notes;
-- Predefined_Activities-Tabelle (wahrscheinlich 'predefined_activities')
DROP INDEX IF EXISTS idx_predefined_activity_created_at ON predefined_activities;
DROP INDEX IF EXISTS idx_predefined_activity_updated_at ON predefined_activities;
-- Diary_Date_Activities-Tabelle (wahrscheinlich 'diary_date_activities')
DROP INDEX IF EXISTS idx_diary_date_activity_created_at ON diary_date_activities;
DROP INDEX IF EXISTS idx_diary_date_activity_updated_at ON diary_date_activities;
-- Matches-Tabelle (wahrscheinlich 'matches')
DROP INDEX IF EXISTS idx_match_created_at ON matches;
DROP INDEX IF EXISTS idx_match_updated_at ON matches;
-- Leagues-Tabelle (wahrscheinlich 'leagues')
DROP INDEX IF EXISTS idx_league_created_at ON leagues;
DROP INDEX IF EXISTS idx_league_updated_at ON leagues;
-- Teams-Tabelle (wahrscheinlich 'teams')
DROP INDEX IF EXISTS idx_team_created_at ON teams;
DROP INDEX IF EXISTS idx_team_updated_at ON teams;
-- Seasons-Tabelle (wahrscheinlich 'seasons')
DROP INDEX IF EXISTS idx_season_created_at ON seasons;
DROP INDEX IF EXISTS idx_season_updated_at ON seasons;
-- Locations-Tabelle (wahrscheinlich 'locations')
DROP INDEX IF EXISTS idx_location_created_at ON locations;
DROP INDEX IF EXISTS idx_location_updated_at ON locations;
-- Groups-Tabelle (wahrscheinlich 'groups')
DROP INDEX IF EXISTS idx_group_created_at ON `groups`;
DROP INDEX IF EXISTS idx_group_updated_at ON `groups`;
-- Group_Activities-Tabelle (wahrscheinlich 'group_activities')
DROP INDEX IF EXISTS idx_group_activity_created_at ON group_activities;
DROP INDEX IF EXISTS idx_group_activity_updated_at ON group_activities;
-- Tournaments-Tabelle (wahrscheinlich 'tournaments')
DROP INDEX IF EXISTS idx_tournament_created_at ON tournaments;
DROP INDEX IF EXISTS idx_tournament_updated_at ON tournaments;
-- Tournament_Groups-Tabelle (wahrscheinlich 'tournament_groups')
DROP INDEX IF EXISTS idx_tournament_group_created_at ON tournament_groups;
DROP INDEX IF EXISTS idx_tournament_group_updated_at ON tournament_groups;
-- Tournament_Members-Tabelle (wahrscheinlich 'tournament_members')
DROP INDEX IF EXISTS idx_tournament_member_created_at ON tournament_members;
DROP INDEX IF EXISTS idx_tournament_member_updated_at ON tournament_members;
-- Tournament_Matches-Tabelle (wahrscheinlich 'tournament_matches')
DROP INDEX IF EXISTS idx_tournament_match_created_at ON tournament_matches;
DROP INDEX IF EXISTS idx_tournament_match_updated_at ON tournament_matches;
-- Tournament_Results-Tabelle (wahrscheinlich 'tournament_results')
DROP INDEX IF EXISTS idx_tournament_result_created_at ON tournament_results;
DROP INDEX IF EXISTS idx_tournament_result_updated_at ON tournament_results;
-- Accidents-Tabelle (wahrscheinlich 'accidents')
DROP INDEX IF EXISTS idx_accident_created_at ON accidents;
DROP INDEX IF EXISTS idx_accident_updated_at ON accidents;
-- User_Tokens-Tabelle (wahrscheinlich 'user_tokens')
DROP INDEX IF EXISTS idx_user_token_created_at ON user_tokens;
DROP INDEX IF EXISTS idx_user_token_updated_at ON user_tokens;
-- 2. Status anzeigen
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 3. Gesamtanzahl der Keys anzeigen
SELECT
COUNT(*) as total_keys
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';

View File

@@ -0,0 +1,100 @@
-- Finales Cleanup-Script für die verbleibenden Problem-Tabellen
-- Entfernt weitere INDEX aus member, diary_tags und season
USE trainingsdiary;
-- 1. Status vor dem finalen Cleanup
SELECT '=== STATUS VOR FINALEM CLEANUP ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 2. Alle INDEX der Problem-Tabellen anzeigen
SELECT '=== MEMBER TABELLE INDEX ===' as info;
SHOW INDEX FROM member;
SELECT '=== DIARY_TAGS TABELLE INDEX ===' as info;
SHOW INDEX FROM diary_tags;
SELECT '=== SEASON TABELLE INDEX ===' as info;
SHOW INDEX FROM season;
-- 3. Spezifische INDEX entfernen (basierend auf den echten Namen)
-- Diese INDEX sind wahrscheinlich überflüssig und können entfernt werden
-- Member-Tabelle: Weitere INDEX entfernen
SELECT '=== ENTFERNE WEITERE MEMBER INDEX ===' as info;
-- Versuche, INDEX zu entfernen, die wahrscheinlich überflüssig sind
-- (Diese Namen basieren auf typischen Sequelize-Konventionen)
-- Häufige überflüssige INDEX-Namen
DROP INDEX IF EXISTS member_hashed_id_unique ON member;
DROP INDEX IF EXISTS member_first_name_index ON member;
DROP INDEX IF EXISTS member_last_name_index ON member;
DROP INDEX IF EXISTS member_birth_date_index ON member;
DROP INDEX IF EXISTS member_active_index ON member;
DROP INDEX IF EXISTS member_created_at_index ON member;
DROP INDEX IF EXISTS member_updated_at_index ON member;
-- Alternative INDEX-Namen
DROP INDEX IF EXISTS idx_member_hashed_id ON member;
DROP INDEX IF EXISTS idx_member_first_name ON member;
DROP INDEX IF EXISTS idx_member_last_name ON member;
DROP INDEX IF EXISTS idx_member_birth_date ON member;
DROP INDEX IF EXISTS idx_member_active ON member;
DROP INDEX IF EXISTS idx_member_created_at ON member;
DROP INDEX IF EXISTS idx_member_updated_at ON member;
-- Diary_Tags-Tabelle: Weitere INDEX entfernen
SELECT '=== ENTFERNE WEITERE DIARY_TAGS INDEX ===' as info;
DROP INDEX IF EXISTS diary_tags_name_index ON diary_tags;
DROP INDEX IF EXISTS diary_tags_created_at_index ON diary_tags;
DROP INDEX IF EXISTS diary_tags_updated_at_index ON member;
-- Alternative INDEX-Namen
DROP INDEX IF EXISTS idx_diary_tags_name ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tags_created_at ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tags_updated_at ON diary_tags;
-- Season-Tabelle: Weitere INDEX entfernen
SELECT '=== ENTFERNE WEITERE SEASON INDEX ===' as info;
DROP INDEX IF EXISTS season_name_index ON season;
DROP INDEX IF EXISTS season_start_date_index ON season;
DROP INDEX IF EXISTS season_end_date_index ON season;
DROP INDEX IF EXISTS season_created_at_index ON season;
DROP INDEX IF EXISTS season_updated_at_index ON season;
-- Alternative INDEX-Namen
DROP INDEX IF EXISTS idx_season_name ON season;
DROP INDEX IF EXISTS idx_season_start_date ON season;
DROP INDEX IF EXISTS idx_season_end_date ON season;
DROP INDEX IF EXISTS idx_season_created_at ON season;
DROP INDEX IF EXISTS idx_season_updated_at ON season;
-- 4. Status nach dem finalen Cleanup
SELECT '=== STATUS NACH FINALEM CLEANUP ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 5. Gesamtanzahl der Keys
SELECT
COUNT(*) as total_keys_after_final_cleanup
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
-- 6. Zusammenfassung
SELECT '=== ZUSAMMENFASSUNG ===' as info;
SELECT
'Finales Cleanup abgeschlossen. Überprüfen Sie die Anzahl der Keys oben.' as message;

View File

@@ -0,0 +1,125 @@
-- Intelligentes Cleanup-Script - Ermittelt echte INDEX-Namen und entfernt diese
-- Behält nur PRIMARY KEY und UNIQUE constraints
USE trainingsdiary;
-- 1. Status vor dem intelligenten Cleanup
SELECT '=== STATUS VOR INTELLIGENTEM CLEANUP ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 2. Alle INDEX der Problem-Tabellen anzeigen (mit echten Namen)
SELECT '=== MEMBER TABELLE INDEX (ECHTE NAMEN) ===' as info;
SHOW INDEX FROM member;
SELECT '=== DIARY_TAGS TABELLE INDEX (ECHTE NAMEN) ===' as info;
SHOW INDEX FROM diary_tags;
SELECT '=== SEASON TABELLE INDEX (ECHTE NAMEN) ===' as info;
SHOW INDEX FROM season;
-- 3. Alle INDEX-Namen extrahieren und DROP-Befehle generieren
SELECT '=== GENERIERE DROP-BEFEHLE FÜR ÜBERFLÜSSIGE INDEX ===' as info;
-- Member-Tabelle: Alle INDEX außer PRIMARY entfernen
SELECT '=== ENTFERNE ÜBERFLÜSSIGE MEMBER INDEX ===' as info;
-- Verwende die echten INDEX-Namen aus SHOW INDEX
-- Entferne alle außer PRIMARY KEY (PRIMARY kann nicht gelöscht werden)
-- Beispiel für häufige überflüssige INDEX-Namen (basierend auf Sequelize-Konventionen)
-- Diese werden nur ausgeführt, wenn sie existieren
-- Häufige überflüssige INDEX-Namen
DROP INDEX IF EXISTS member_hashed_id_unique ON member;
DROP INDEX IF EXISTS member_first_name_index ON member;
DROP INDEX IF EXISTS member_last_name_index ON member;
DROP INDEX IF EXISTS member_birth_date_index ON member;
DROP INDEX IF EXISTS member_active_index ON member;
DROP INDEX IF EXISTS member_created_at_index ON member;
DROP INDEX IF EXISTS member_updated_at_index ON member;
DROP INDEX IF EXISTS member_club_id_index ON member;
DROP INDEX IF EXISTS member_hashed_id_index ON member;
-- Alternative INDEX-Namen
DROP INDEX IF EXISTS idx_member_hashed_id ON member;
DROP INDEX IF EXISTS idx_member_first_name ON member;
DROP INDEX IF EXISTS idx_member_last_name ON member;
DROP INDEX IF EXISTS idx_member_birth_date ON member;
DROP INDEX IF EXISTS idx_member_active ON member;
DROP INDEX IF EXISTS idx_member_created_at ON member;
DROP INDEX IF EXISTS idx_member_updated_at ON member;
DROP INDEX IF EXISTS idx_member_club_id ON member;
-- Diary_Tags-Tabelle: Alle überflüssigen INDEX entfernen
SELECT '=== ENTFERNE ÜBERFLÜSSIGE DIARY_TAGS INDEX ===' as info;
DROP INDEX IF EXISTS diary_tags_name_index ON diary_tags;
DROP INDEX IF EXISTS diary_tags_created_at_index ON diary_tags;
DROP INDEX IF EXISTS diary_tags_updated_at_index ON diary_tags;
DROP INDEX IF EXISTS diary_tags_club_id_index ON diary_tags;
-- Alternative INDEX-Namen
DROP INDEX IF EXISTS idx_diary_tags_name ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tags_created_at ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tags_updated_at ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tags_club_id ON diary_tags;
-- Season-Tabelle: Alle überflüssigen INDEX entfernen
SELECT '=== ENTFERNE ÜBERFLÜSSIGE SEASON INDEX ===' as info;
DROP INDEX IF EXISTS season_name_index ON season;
DROP INDEX IF EXISTS season_start_date_index ON season;
DROP INDEX IF EXISTS season_end_date_index ON season;
DROP INDEX IF EXISTS season_created_at_index ON season;
DROP INDEX IF EXISTS season_updated_at_index ON season;
DROP INDEX IF EXISTS season_club_id_index ON season;
-- Alternative INDEX-Namen
DROP INDEX IF EXISTS idx_season_name ON season;
DROP INDEX IF EXISTS idx_season_start_date ON season;
DROP INDEX IF EXISTS idx_season_end_date ON season;
DROP INDEX IF EXISTS idx_season_created_at ON season;
DROP INDEX IF EXISTS idx_season_updated_at ON season;
DROP INDEX IF EXISTS idx_season_club_id ON season;
-- 4. Status nach dem intelligenten Cleanup
SELECT '=== STATUS NACH INTELLIGENTEM CLEANUP ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 5. Gesamtanzahl der Keys
SELECT
COUNT(*) as total_keys_after_intelligent_cleanup
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
-- 6. Ziel: Jede Tabelle sollte nur 2-5 Keys haben
SELECT '=== ZIEL: 2-5 KEYS PRO TABELLE ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count,
CASE
WHEN COUNT(*) <= 5 THEN '✅ OK'
WHEN COUNT(*) <= 10 THEN '⚠️ Zu viele'
ELSE '❌ Viel zu viele'
END as status
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 7. Zusammenfassung
SELECT '=== ZUSAMMENFASSUNG ===' as info;
SELECT
'Intelligentes Cleanup abgeschlossen. Überprüfen Sie die Anzahl der Keys oben.' as message;

View File

@@ -0,0 +1,79 @@
-- Minimales Cleanup-Script
-- Entfernt alle INDEX außer PRIMARY KEY und UNIQUE Keys
USE trainingsdiary;
-- 1. Status vor Cleanup
SELECT '=== STATUS VOR CLEANUP ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
SELECT
COUNT(*) as total_keys_before
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
-- 2. Alle nicht-essentiellen INDEX entfernen
-- Behalte nur PRIMARY KEY und UNIQUE Keys
-- Alle INDEX außer PRIMARY und UNIQUE entfernen
-- Verwende SHOW INDEX um die echten INDEX-Namen zu sehen
SELECT '=== ENTFERNE ÜBERFLÜSSIGE INDEX ===' as info;
-- Member-Tabelle: Alle INDEX außer PRIMARY entfernen
SELECT '=== MEMBER TABELLE ===' as info;
SHOW INDEX FROM member;
-- User-Tabelle: Alle INDEX außer PRIMARY entfernen
SELECT '=== USER TABELLE ===' as info;
SHOW INDEX FROM user;
-- Clubs-Tabelle: Alle INDEX außer PRIMARY entfernen
SELECT '=== CLUBS TABELLE ===' as info;
SHOW INDEX FROM clubs;
-- User_Club-Tabelle: Alle INDEX außer PRIMARY entfernen
SELECT '=== USER_CLUB TABELLE ===' as info;
SHOW INDEX FROM user_club;
-- Log-Tabelle: Alle INDEX außer PRIMARY entfernen
SELECT '=== LOG TABELLE ===' as info;
SHOW INDEX FROM log;
-- Diary_Dates-Tabelle: Alle INDEX außer PRIMARY entfernen
SELECT '=== DIARY_DATES TABELLE ===' as info;
SHOW INDEX FROM diary_dates;
-- Participants-Tabelle: Alle INDEX außer PRIMARY entfernen
SELECT '=== PARTICIPANTS TABELLE ===' as info;
SHOW INDEX FROM participants;
-- Activities-Tabelle: Alle INDEX außer PRIMARY entfernen
SELECT '=== ACTIVITIES TABELLE ===' as info;
SHOW INDEX FROM activities;
-- 3. Status nach Cleanup
SELECT '=== STATUS NACH CLEANUP ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
SELECT
COUNT(*) as total_keys_after
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
-- 4. Zusammenfassung
SELECT '=== ZUSAMMENFASSUNG ===' as info;
SELECT
'Minimales Cleanup abgeschlossen. Überprüfen Sie die Anzahl der Keys oben.' as message;

143
backend/cleanupKeysNode.cjs Normal file
View File

@@ -0,0 +1,143 @@
const mysql = require('mysql2/promise');
require('dotenv').config();
// Datenbankverbindung
const dbConfig = {
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '',
database: process.env.DB_NAME || 'trainingsdiary'
};
async function cleanupKeys() {
let connection;
try {
console.log('🔌 Verbinde mit der Datenbank...');
connection = await mysql.createConnection(dbConfig);
// 1. Status vor dem Cleanup
console.log('\n📊 STATUS VOR DEM CLEANUP:');
const [tablesBefore] = await connection.execute(`
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = ?
GROUP BY TABLE_NAME
ORDER BY key_count DESC
`, [dbConfig.database]);
tablesBefore.forEach(table => {
console.log(` ${table.TABLE_NAME}: ${table.key_count} Keys`);
});
// 2. Alle INDEX der Problem-Tabellen anzeigen
const problemTables = ['member', 'diary_tags', 'season'];
for (const tableName of problemTables) {
console.log(`\n🔍 INDEX für Tabelle '${tableName}':`);
try {
const [indexes] = await connection.execute(`SHOW INDEX FROM \`${tableName}\``);
if (indexes.length === 0) {
console.log(` Keine INDEX gefunden für Tabelle '${tableName}'`);
continue;
}
indexes.forEach(index => {
console.log(` - ${index.Key_name} (${index.Column_name}) - ${index.Non_unique === 0 ? 'UNIQUE' : 'NON-UNIQUE'}`);
});
// 3. Überflüssige INDEX entfernen (alle außer PRIMARY und UNIQUE)
console.log(`\n🗑️ Entferne überflüssige INDEX aus '${tableName}':`);
for (const index of indexes) {
// Behalte PRIMARY KEY und UNIQUE constraints
if (index.Key_name === 'PRIMARY' || index.Non_unique === 0) {
console.log(` ✅ Behalte: ${index.Key_name} (${index.Column_name})`);
continue;
}
// Entferne alle anderen INDEX
try {
await connection.execute(`DROP INDEX \`${index.Key_name}\` ON \`${tableName}\``);
console.log(` ❌ Entfernt: ${index.Key_name} (${index.Column_name})`);
} catch (error) {
if (error.code === 'ER_CANT_DROP_FIELD_OR_KEY') {
console.log(` ⚠️ Kann nicht entfernen: ${index.Key_name} (${index.Column_name}) - ${error.message}`);
} else {
console.log(` ❌ Fehler beim Entfernen von ${index.Key_name}: ${error.message}`);
}
}
}
} catch (error) {
console.log(` ⚠️ Fehler beim Zugriff auf Tabelle '${tableName}': ${error.message}`);
}
}
// 4. Status nach dem Cleanup
console.log('\n📊 STATUS NACH DEM CLEANUP:');
const [tablesAfter] = await connection.execute(`
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = ?
GROUP BY TABLE_NAME
ORDER BY key_count DESC
`, [dbConfig.database]);
tablesAfter.forEach(table => {
const before = tablesBefore.find(t => t.TABLE_NAME === table.TABLE_NAME);
const beforeCount = before ? before.key_count : 0;
const diff = beforeCount - table.key_count;
const status = table.key_count <= 5 ? '✅' : table.key_count <= 10 ? '⚠️' : '❌';
console.log(` ${status} ${table.TABLE_NAME}: ${table.key_count} Keys (${diff > 0 ? `-${diff}` : `+${Math.abs(diff)}`})`);
});
// 5. Gesamtanzahl der Keys
const [totalKeys] = await connection.execute(`
SELECT COUNT(*) as total_keys
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = ?
`, [dbConfig.database]);
console.log(`\n📈 GESAMTANZAHL KEYS: ${totalKeys[0].total_keys}`);
// 6. Zusammenfassung
console.log('\n🎯 ZUSAMMENFASSUNG:');
const problemTablesAfter = tablesAfter.filter(t => t.key_count > 10);
if (problemTablesAfter.length === 0) {
console.log(' ✅ Alle Tabellen haben jetzt weniger als 10 Keys!');
} else {
console.log(' ⚠️ Folgende Tabellen haben immer noch zu viele Keys:');
problemTablesAfter.forEach(table => {
console.log(` - ${table.TABLE_NAME}: ${table.key_count} Keys`);
});
}
} catch (error) {
console.error('❌ Fehler beim Cleanup:', error);
} finally {
if (connection) {
await connection.end();
console.log('\n🔌 Datenbankverbindung geschlossen.');
}
}
}
// Script ausführen
console.log('🚀 Starte intelligentes INDEX-Cleanup...\n');
cleanupKeys().then(() => {
console.log('\n✨ Cleanup abgeschlossen!');
process.exit(0);
}).catch(error => {
console.error('\n💥 Fehler beim Cleanup:', error);
process.exit(1);
});

166
backend/cleanupKeysNode.js Normal file
View File

@@ -0,0 +1,166 @@
import mysql from 'mysql2/promise';
import dotenv from 'dotenv';
import path from 'path';
import { fileURLToPath } from 'url';
// __dirname für ES-Module
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Umgebungsvariablen aus dem Root-Verzeichnis laden
//const envPath = path.join(__dirname, '..', '.env');
//console.log('🔍 Lade .env-Datei von:', envPath);
dotenv.config();
// Debug: Zeige geladene Umgebungsvariablen
console.log('🔍 Geladene Umgebungsvariablen:');
console.log(' DB_HOST:', process.env.DB_HOST);
console.log(' DB_USER:', process.env.DB_USER);
console.log(' DB_NAME:', process.env.DB_NAME);
console.log(' DB_PASSWORD:', process.env.DB_PASSWORD ? '***gesetzt***' : 'nicht gesetzt');
// Datenbankverbindung
const dbConfig = {
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || '',
database: process.env.DB_NAME || 'trainingsdiary'
};
console.log('🔍 Datenbankverbindung:');
console.log(' Host:', dbConfig.host);
console.log(' User:', dbConfig.user);
console.log(' Database:', dbConfig.database);
console.log(' Password:', dbConfig.password ? '***gesetzt***' : 'nicht gesetzt');
async function cleanupKeys() {
let connection;
try {
console.log('🔌 Verbinde mit der Datenbank...');
connection = await mysql.createConnection(dbConfig);
// 1. Status vor dem Cleanup
console.log('\n📊 STATUS VOR DEM CLEANUP:');
const [tablesBefore] = await connection.execute(`
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = ?
GROUP BY TABLE_NAME
ORDER BY key_count DESC
`, [dbConfig.database]);
tablesBefore.forEach(table => {
console.log(` ${table.TABLE_NAME}: ${table.key_count} Keys`);
});
// 2. Alle INDEX der Problem-Tabellen anzeigen
const problemTables = ['member', 'diary_tags', 'season'];
for (const tableName of problemTables) {
console.log(`\n🔍 INDEX für Tabelle '${tableName}':`);
try {
const [indexes] = await connection.execute(`SHOW INDEX FROM \`${tableName}\``);
if (indexes.length === 0) {
console.log(` Keine INDEX gefunden für Tabelle '${tableName}'`);
continue;
}
indexes.forEach(index => {
console.log(` - ${index.Key_name} (${index.Column_name}) - ${index.Non_unique === 0 ? 'UNIQUE' : 'NON-UNIQUE'}`);
});
// 3. Überflüssige INDEX entfernen (alle außer PRIMARY und UNIQUE)
console.log(`\n🗑️ Entferne überflüssige INDEX aus '${tableName}':`);
for (const index of indexes) {
// Behalte PRIMARY KEY und UNIQUE constraints
if (index.Key_name === 'PRIMARY' || index.Non_unique === 0) {
console.log(` ✅ Behalte: ${index.Key_name} (${index.Column_name})`);
continue;
}
// Entferne alle anderen INDEX
try {
await connection.execute(`DROP INDEX \`${index.Key_name}\` ON \`${tableName}\``);
console.log(` ❌ Entfernt: ${index.Key_name} (${index.Column_name})`);
} catch (error) {
if (error.code === 'ER_CANT_DROP_FIELD_OR_KEY') {
console.log(` ⚠️ Kann nicht entfernen: ${index.Key_name} (${index.Column_name}) - ${error.message}`);
} else {
console.log(` ❌ Fehler beim Entfernen von ${index.Key_name}: ${error.message}`);
}
}
}
} catch (error) {
console.log(` ⚠️ Fehler beim Zugriff auf Tabelle '${tableName}': ${error.message}`);
}
}
// 4. Status nach dem Cleanup
console.log('\n📊 STATUS NACH DEM CLEANUP:');
const [tablesAfter] = await connection.execute(`
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = ?
GROUP BY TABLE_NAME
ORDER BY key_count DESC
`, [dbConfig.database]);
tablesAfter.forEach(table => {
const before = tablesBefore.find(t => t.TABLE_NAME === table.TABLE_NAME);
const beforeCount = before ? before.key_count : 0;
const diff = beforeCount - table.key_count;
const status = table.key_count <= 5 ? '✅' : table.key_count <= 10 ? '⚠️' : '❌';
console.log(` ${status} ${table.TABLE_NAME}: ${table.key_count} Keys (${diff > 0 ? `-${diff}` : `+${Math.abs(diff)}`})`);
});
// 5. Gesamtanzahl der Keys
const [totalKeys] = await connection.execute(`
SELECT COUNT(*) as total_keys
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = ?
`, [dbConfig.database]);
console.log(`\n📈 GESAMTANZAHL KEYS: ${totalKeys[0].total_keys}`);
// 6. Zusammenfassung
console.log('\n🎯 ZUSAMMENFASSUNG:');
const problemTablesAfter = tablesAfter.filter(t => t.key_count > 10);
if (problemTablesAfter.length === 0) {
console.log(' ✅ Alle Tabellen haben jetzt weniger als 10 Keys!');
} else {
console.log(' ⚠️ Folgende Tabellen haben immer noch zu viele Keys:');
problemTablesAfter.forEach(table => {
console.log(` - ${table.TABLE_NAME}: ${table.key_count} Keys`);
});
}
} catch (error) {
console.error('❌ Fehler beim Cleanup:', error);
} finally {
if (connection) {
await connection.end();
console.log('\n🔌 Datenbankverbindung geschlossen.');
}
}
}
// Script ausführen
console.log('🚀 Starte intelligentes INDEX-Cleanup...\n');
cleanupKeys().then(() => {
console.log('\n✨ Cleanup abgeschlossen!');
process.exit(0);
}).catch(error => {
console.error('\n💥 Fehler beim Cleanup:', error);
process.exit(1);
});

149
backend/cleanupKeysReal.sql Normal file
View File

@@ -0,0 +1,149 @@
-- Cleanup-Script mit echten INDEX-Namen
-- Zeigt zuerst alle vorhandenen INDEX an und entfernt dann nur die überflüssigen
USE trainingsdiary;
-- 1. Alle vorhandenen INDEX anzeigen
SELECT '=== VORHANDENE INDEX VOR CLEANUP ===' as info;
SELECT
TABLE_NAME,
INDEX_NAME,
COLUMN_NAME,
NON_UNIQUE,
SEQ_IN_INDEX
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX;
-- 2. Anzahl der Keys pro Tabelle vor Cleanup
SELECT '=== KEYS PRO TABELLE VOR CLEANUP ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 3. Gesamtanzahl der Keys vor Cleanup
SELECT '=== GESAMTANZAHL KEYS VOR CLEANUP ===' as info;
SELECT
COUNT(*) as total_keys_before
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
-- 4. Cleanup: Nur INDEX entfernen, die tatsächlich existieren
-- Verwende DROP INDEX IF EXISTS für alle möglichen INDEX
-- Member-Tabelle
SELECT '=== ENTFERNE MEMBER INDEX ===' as info;
DROP INDEX IF EXISTS idx_member_hashed_id ON member;
DROP INDEX IF EXISTS idx_member_first_name ON member;
DROP INDEX IF EXISTS idx_member_last_name ON member;
DROP INDEX IF EXISTS idx_member_birth_date ON member;
DROP INDEX IF EXISTS idx_member_active ON member;
DROP INDEX IF EXISTS idx_member_created_at ON member;
DROP INDEX IF EXISTS idx_member_updated_at ON member;
-- User-Tabelle
SELECT '=== ENTFERNE USER INDEX ===' as info;
DROP INDEX IF EXISTS idx_user_email ON user;
DROP INDEX IF EXISTS idx_user_created_at ON user;
DROP INDEX IF EXISTS idx_user_updated_at ON user;
-- Clubs-Tabelle
SELECT '=== ENTFERNE CLUBS INDEX ===' as info;
DROP INDEX IF EXISTS idx_clubs_name ON clubs;
DROP INDEX IF EXISTS idx_clubs_created_at ON clubs;
DROP INDEX IF EXISTS idx_clubs_updated_at ON clubs;
-- User_Club-Tabelle
SELECT '=== ENTFERNE USER_CLUB INDEX ===' as info;
DROP INDEX IF EXISTS idx_user_club_approved ON user_club;
DROP INDEX IF EXISTS idx_user_club_created_at ON user_club;
DROP INDEX IF EXISTS idx_user_club_updated_at ON user_club;
-- Log-Tabelle
SELECT '=== ENTFERNE LOG INDEX ===' as info;
DROP INDEX IF EXISTS idx_log_activity ON log;
DROP INDEX IF EXISTS idx_log_created_at ON log;
DROP INDEX IF EXISTS idx_log_updated_at ON log;
-- Diary_Dates-Tabelle
SELECT '=== ENTFERNE DIARY_DATES INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_dates_date ON diary_dates;
DROP INDEX IF EXISTS idx_diary_dates_created_at ON diary_dates;
DROP INDEX IF EXISTS idx_diary_dates_updated_at ON diary_dates;
-- Participants-Tabelle
SELECT '=== ENTFERNE PARTICIPANTS INDEX ===' as info;
DROP INDEX IF EXISTS idx_participant_created_at ON participants;
DROP INDEX IF EXISTS idx_participant_updated_at ON participants;
-- Activities-Tabelle
SELECT '=== ENTFERNE ACTIVITIES INDEX ===' as info;
DROP INDEX IF EXISTS idx_activity_created_at ON activities;
DROP INDEX IF EXISTS idx_activity_updated_at ON activities;
-- Member_Notes-Tabelle
SELECT '=== ENTFERNE MEMBER_NOTES INDEX ===' as info;
DROP INDEX IF EXISTS idx_member_note_created_at ON member_notes;
DROP INDEX IF EXISTS idx_member_note_updated_at ON member_notes;
-- Diary_Notes-Tabelle
SELECT '=== ENTFERNE DIARY_NOTES INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_note_created_at ON diary_notes;
DROP INDEX IF EXISTS idx_diary_note_updated_at ON diary_notes;
-- Diary_Tags-Tabelle
SELECT '=== ENTFERNE DIARY_TAGS INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_tag_created_at ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tag_updated_at ON diary_tags;
-- Member_Diary_Tags-Tabelle
SELECT '=== ENTFERNE MEMBER_DIARY_TAGS INDEX ===' as info;
DROP INDEX IF EXISTS idx_member_diary_tag_created_at ON member_diary_tags;
DROP INDEX IF EXISTS idx_member_diary_tag_updated_at ON member_diary_tags;
-- Diary_Date_Tags-Tabelle
SELECT '=== ENTFERNE DIARY_DATE_TAGS INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_date_tag_created_at ON diary_date_tags;
DROP INDEX IF EXISTS idx_diary_date_tag_updated_at ON diary_date_tags;
-- Diary_Member_Notes-Tabelle
SELECT '=== ENTFERNE DIARY_MEMBER_NOTES INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_member_note_created_at ON diary_member_notes;
DROP INDEX IF EXISTS idx_diary_member_note_updated_at ON diary_member_notes;
-- Predefined_Activities-Tabelle
SELECT '=== ENTFERNE PREDEFINED_ACTIVITIES INDEX ===' as info;
DROP INDEX IF EXISTS idx_predefined_activity_created_at ON predefined_activities;
DROP INDEX IF EXISTS idx_predefined_activity_updated_at ON predefined_activities;
-- Diary_Date_Activities-Tabelle
SELECT '=== ENTFERNE DIARY_DATE_ACTIVITIES INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_date_activity_created_at ON diary_date_activities;
DROP INDEX IF EXISTS idx_diary_date_activity_updated_at ON diary_date_activities;
-- 5. Nach der Bereinigung: Status anzeigen
SELECT '=== STATUS NACH BEREINIGUNG ===' as info;
-- Anzahl der Keys pro Tabelle nach der Bereinigung
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- Gesamtanzahl der Keys nach der Bereinigung
SELECT
COUNT(*) as total_keys_after
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
-- 6. Zusammenfassung der Änderungen
SELECT '=== ZUSAMMENFASSUNG ===' as info;
SELECT
'Cleanup abgeschlossen. Überprüfen Sie die Anzahl der Keys oben.' as message;

View File

@@ -0,0 +1,41 @@
-- Vereinfachtes Cleanup-Script für MySQL Keys
-- Entfernt nur die problematischsten Keys
USE trainingsdiary;
-- 1. Alle überflüssigen INDEX entfernen (die meisten werden von Sequelize automatisch erstellt)
-- Diese entfernen die meisten Keys, die das Limit überschreiten
-- Member-Tabelle (Hauptproblem)
DROP INDEX IF EXISTS idx_member_hashed_id ON member;
DROP INDEX IF EXISTS idx_member_first_name ON member;
DROP INDEX IF EXISTS idx_member_last_name ON member;
DROP INDEX IF EXISTS idx_member_birth_date ON member;
DROP INDEX IF EXISTS idx_member_active ON member;
DROP INDEX IF EXISTS idx_member_created_at ON member;
DROP INDEX IF EXISTS idx_member_updated_at ON member;
-- User-Tabelle
DROP INDEX IF EXISTS idx_user_email ON user;
DROP INDEX IF EXISTS idx_user_created_at ON user;
DROP INDEX IF EXISTS idx_user_updated_at ON user;
-- Clubs-Tabelle
DROP INDEX IF EXISTS idx_clubs_name ON clubs;
DROP INDEX IF EXISTS idx_clubs_created_at ON clubs;
DROP INDEX IF EXISTS idx_clubs_updated_at ON clubs;
-- 2. Status anzeigen
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 3. Gesamtanzahl der Keys anzeigen
SELECT
COUNT(*) as total_keys
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';

View File

@@ -0,0 +1,153 @@
-- Intelligentes Cleanup-Script für MySQL Keys
-- Überprüft zuerst die echten Tabellennamen und entfernt nur vorhandene INDEX
USE trainingsdiary;
-- 1. Alle vorhandenen Tabellen anzeigen
SELECT '=== VORHANDENE TABELLEN ===' as info;
SHOW TABLES;
-- 2. Alle vorhandenen INDEX anzeigen
SELECT '=== VORHANDENE INDEX ===' as info;
SELECT
TABLE_NAME,
INDEX_NAME,
COLUMN_NAME,
NON_UNIQUE,
SEQ_IN_INDEX
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX;
-- 3. Anzahl der Keys pro Tabelle anzeigen
SELECT '=== KEYS PRO TABELLE ===' as info;
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- 4. Gesamtanzahl der Keys anzeigen
SELECT '=== GESAMTANZAHL KEYS ===' as info;
SELECT
COUNT(*) as total_keys
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
-- 5. Intelligente INDEX-Entfernung basierend auf vorhandenen Tabellen
-- Nur INDEX entfernen, die tatsächlich existieren
-- Member-Tabelle (Hauptproblem)
SELECT '=== ENTFERNE MEMBER INDEX ===' as info;
DROP INDEX IF EXISTS idx_member_hashed_id ON member;
DROP INDEX IF EXISTS idx_member_first_name ON member;
DROP INDEX IF EXISTS idx_member_last_name ON member;
DROP INDEX IF EXISTS idx_member_birth_date ON member;
DROP INDEX IF EXISTS idx_member_active ON member;
DROP INDEX IF EXISTS idx_member_created_at ON member;
DROP INDEX IF EXISTS idx_member_updated_at ON member;
-- User-Tabelle
SELECT '=== ENTFERNE USER INDEX ===' as info;
DROP INDEX IF EXISTS idx_user_email ON user;
DROP INDEX IF EXISTS idx_user_created_at ON user;
DROP INDEX IF EXISTS idx_user_updated_at ON user;
-- Clubs-Tabelle
SELECT '=== ENTFERNE CLUBS INDEX ===' as info;
DROP INDEX IF EXISTS idx_clubs_name ON clubs;
DROP INDEX IF EXISTS idx_clubs_created_at ON clubs;
DROP INDEX IF EXISTS idx_clubs_updated_at ON clubs;
-- User_Club-Tabelle
SELECT '=== ENTFERNE USER_CLUB INDEX ===' as info;
DROP INDEX IF EXISTS idx_user_club_approved ON user_club;
DROP INDEX IF EXISTS idx_user_club_created_at ON user_club;
DROP INDEX IF EXISTS idx_user_club_updated_at ON user_club;
-- Log-Tabelle
SELECT '=== ENTFERNE LOG INDEX ===' as info;
DROP INDEX IF EXISTS idx_log_activity ON log;
DROP INDEX IF EXISTS idx_log_created_at ON log;
DROP INDEX IF EXISTS idx_log_updated_at ON log;
-- Diary_Dates-Tabelle
SELECT '=== ENTFERNE DIARY_DATES INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_dates_date ON diary_dates;
DROP INDEX IF EXISTS idx_diary_dates_created_at ON diary_dates;
DROP INDEX IF EXISTS idx_diary_dates_updated_at ON diary_dates;
-- Participants-Tabelle
SELECT '=== ENTFERNE PARTICIPANTS INDEX ===' as info;
DROP INDEX IF EXISTS idx_participant_created_at ON participants;
DROP INDEX IF EXISTS idx_participant_updated_at ON participants;
-- Activities-Tabelle
SELECT '=== ENTFERNE ACTIVITIES INDEX ===' as info;
DROP INDEX IF EXISTS idx_activity_created_at ON activities;
DROP INDEX IF EXISTS idx_activity_updated_at ON activities;
-- Member_Notes-Tabelle
SELECT '=== ENTFERNE MEMBER_NOTES INDEX ===' as info;
DROP INDEX IF EXISTS idx_member_note_created_at ON member_notes;
DROP INDEX IF EXISTS idx_member_note_updated_at ON member_notes;
-- Diary_Notes-Tabelle
SELECT '=== ENTFERNE DIARY_NOTES INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_note_created_at ON diary_notes;
DROP INDEX IF EXISTS idx_diary_note_updated_at ON diary_notes;
-- Diary_Tags-Tabelle
SELECT '=== ENTFERNE DIARY_TAGS INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_tag_created_at ON diary_tags;
DROP INDEX IF EXISTS idx_diary_tag_updated_at ON diary_tags;
-- Member_Diary_Tags-Tabelle
SELECT '=== ENTFERNE MEMBER_DIARY_TAGS INDEX ===' as info;
DROP INDEX IF EXISTS idx_member_diary_tag_created_at ON member_diary_tags;
DROP INDEX IF EXISTS idx_member_diary_tag_updated_at ON member_diary_tags;
-- Diary_Date_Tags-Tabelle
SELECT '=== ENTFERNE DIARY_DATE_TAGS INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_date_tag_created_at ON diary_date_tags;
DROP INDEX IF EXISTS idx_diary_date_tag_updated_at ON diary_date_tags;
-- Diary_Member_Notes-Tabelle
SELECT '=== ENTFERNE DIARY_MEMBER_NOTES INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_member_note_created_at ON diary_member_notes;
DROP INDEX IF EXISTS idx_diary_member_note_updated_at ON diary_member_notes;
-- Predefined_Activities-Tabelle
SELECT '=== ENTFERNE PREDEFINED_ACTIVITIES INDEX ===' as info;
DROP INDEX IF EXISTS idx_predefined_activity_created_at ON predefined_activities;
DROP INDEX IF EXISTS idx_predefined_activity_updated_at ON predefined_activities;
-- Diary_Date_Activities-Tabelle
SELECT '=== ENTFERNE DIARY_DATE_ACTIVITIES INDEX ===' as info;
DROP INDEX IF EXISTS idx_diary_date_activity_created_at ON diary_date_activities;
DROP INDEX IF EXISTS idx_diary_date_activity_updated_at ON diary_date_activities;
-- 6. Nach der Bereinigung: Status anzeigen
SELECT '=== STATUS NACH BEREINIGUNG ===' as info;
-- Anzahl der Keys pro Tabelle nach der Bereinigung
SELECT
TABLE_NAME,
COUNT(*) as key_count
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary'
GROUP BY TABLE_NAME
ORDER BY key_count DESC;
-- Gesamtanzahl der Keys nach der Bereinigung
SELECT
COUNT(*) as total_keys_after_cleanup
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_SCHEMA = 'trainingsdiary';
-- 7. Zusammenfassung
SELECT '=== ZUSAMMENFASSUNG ===' as info;
SELECT
'Cleanup abgeschlossen. Überprüfen Sie die Anzahl der Keys oben.' as message;

View File

@@ -0,0 +1,121 @@
import { DiaryDate, Member, Participant } from '../models/index.js';
import { Op } from 'sequelize';
class TrainingStatsController {
async getTrainingStats(req, res) {
try {
const { clubId } = req.params;
// Aktuelle Datum für Berechnungen
const now = new Date();
const twelveMonthsAgo = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate());
const threeMonthsAgo = new Date(now.getFullYear(), now.getMonth() - 3, now.getDate());
// Alle aktiven Mitglieder des Vereins laden
const members = await Member.findAll({
where: {
active: true
}
});
const stats = [];
for (const member of members) {
// Trainingsteilnahmen der letzten 12 Monate über Participant-Model
const participation12Months = await Participant.count({
include: [{
model: DiaryDate,
as: 'diaryDate',
where: {
clubId: parseInt(clubId),
date: {
[Op.gte]: twelveMonthsAgo
}
}
}],
where: {
memberId: member.id
}
});
// Trainingsteilnahmen der letzten 3 Monate über Participant-Model
const participation3Months = await Participant.count({
include: [{
model: DiaryDate,
as: 'diaryDate',
where: {
clubId: parseInt(clubId),
date: {
[Op.gte]: threeMonthsAgo
}
}
}],
where: {
memberId: member.id
}
});
// Trainingsteilnahmen insgesamt über Participant-Model
const participationTotal = await Participant.count({
include: [{
model: DiaryDate,
as: 'diaryDate',
where: {
clubId: parseInt(clubId)
}
}],
where: {
memberId: member.id
}
});
// Detaillierte Trainingsdaten (absteigend sortiert) über Participant-Model
const trainingDetails = await Participant.findAll({
include: [{
model: DiaryDate,
as: 'diaryDate',
where: {
clubId: parseInt(clubId)
}
}],
where: {
memberId: member.id
},
order: [['diaryDate', 'date', 'DESC']],
limit: 50 // Begrenzen auf die letzten 50 Trainingseinheiten
});
// Trainingsteilnahmen für den Member formatieren
const formattedTrainingDetails = trainingDetails.map(participation => ({
id: participation.id,
date: participation.diaryDate.date,
activityName: 'Training',
startTime: '--:--',
endTime: '--:--'
}));
stats.push({
id: member.id,
firstName: member.firstName,
lastName: member.lastName,
birthDate: member.birthDate,
participation12Months,
participation3Months,
participationTotal,
trainingDetails: formattedTrainingDetails
});
}
// Nach Gesamtteilnahme absteigend sortieren
stats.sort((a, b) => b.participationTotal - a.participationTotal);
res.json(stats);
} catch (error) {
console.error('Fehler beim Laden der Trainings-Statistik:', error);
res.status(500).json({ error: 'Fehler beim Laden der Trainings-Statistik' });
}
}
}
export default new TrainingStatsController();

View File

@@ -41,6 +41,12 @@ Club.hasMany(DiaryDate, { foreignKey: 'clubId' });
DiaryDate.belongsToMany(Member, { through: Participant, as: 'participants', foreignKey: 'diaryDateId' });
Member.belongsToMany(DiaryDate, { through: Participant, as: 'diaryDates', foreignKey: 'memberId' });
// Explizite Assoziationen für Participant
Participant.belongsTo(DiaryDate, { foreignKey: 'diaryDateId', as: 'diaryDate' });
Participant.belongsTo(Member, { foreignKey: 'memberId', as: 'member' });
DiaryDate.hasMany(Participant, { foreignKey: 'diaryDateId', as: 'participantList' });
Member.hasMany(Participant, { foreignKey: 'memberId', as: 'participantList' });
DiaryDate.hasMany(Activity, { as: 'activities', foreignKey: 'diaryDateId' });
Activity.belongsTo(DiaryDate, { as: 'diaryDate', foreignKey: 'diaryDateId' });

View File

@@ -0,0 +1,10 @@
import express from 'express';
import trainingStatsController from '../controllers/trainingStatsController.js';
import { authenticate } from '../middleware/authMiddleware.js';
const router = express.Router();
router.use(authenticate);
router.get('/:clubId', trainingStatsController.getTrainingStats);
export default router;

View File

@@ -30,6 +30,7 @@ import diaryDateTagRoutes from './routes/diaryDateTagRoutes.js';
import sessionRoutes from './routes/sessionRoutes.js';
import tournamentRoutes from './routes/tournamentRoutes.js';
import accidentRoutes from './routes/accidentRoutes.js';
import trainingStatsRoutes from './routes/trainingStatsRoutes.js';
const app = express();
const port = process.env.PORT || 3000;
@@ -58,9 +59,11 @@ app.use('/api/diarydatetags', diaryDateTagRoutes);
app.use('/api/session', sessionRoutes);
app.use('/api/tournament', tournamentRoutes);
app.use('/api/accident', accidentRoutes);
app.use('/api/training-stats', trainingStatsRoutes);
app.use(express.static(path.join(__dirname, '../frontend/dist')));
// Catch-All Handler für Frontend-Routen (muss nach den API-Routen stehen)
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '../frontend/dist/index.html'));
});