-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ae37be1
Showing
14 changed files
with
802 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
name: Go CI | ||
|
||
# Le workflow s'exécute sur chaque push ou pull request vers les branches principales | ||
on: | ||
workflow_dispatch: | ||
inputs: | ||
gosqlcleaner: | ||
description: 'Version du build' | ||
required: true | ||
|
||
jobs: | ||
build: | ||
# Utilisation de la machine virtuelle ubuntu-latest | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
# Vérifier le code depuis GitHub | ||
- name: Checkout code | ||
uses: actions/checkout@v3 | ||
|
||
# Installer Go | ||
- name: Set up Go | ||
uses: actions/setup-go@v4 | ||
with: | ||
go-version: '1.23.1' # Spécifiez ici la version de Go que vous utilisez | ||
|
||
# Installer les dépendances Go (go.mod et go.sum doivent être présents) | ||
- name: Install dependencies | ||
run: go mod download | ||
|
||
- name: Build | ||
run: go build -v . | ||
|
||
- name: Creating release | ||
uses: softprops/action-gh-release@v2 | ||
with: | ||
tag_name: ${{ github.event.inputs.gosqlcleaner }} | ||
name: ${{ github.event.inputs.gosqlcleaner }} | ||
draft: false | ||
prerelease: false | ||
files: | | ||
package/linux/* | ||
package/windows/* | ||
token: ${{ secrets.GITHUB_TOKEN }} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/docker-compose.yaml | ||
config.json | ||
go.sum | ||
.postgres_data | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<div align=center> | ||
<img src="/assets/dbcleaner.png" width="100px" height="100px" alt="DBCleaner" align="center" /> | ||
<h1>DBCleaner</h1> | ||
</div> | ||
|
||
## Description | ||
|
||
DBCleaner is a program made to be run on the backend of a server or an application to clean the database. It will reduce | ||
the storage of the database and optimise all tables except system tables. It is a simple and efficient way to keep your | ||
database clean and optimised without having to do it manually. It is a great way to keep your database running in the | ||
best | ||
conditions possible. Using Go language, it is compatible with all platforms and can be run on any server or application. | ||
|
||
## Features | ||
|
||
<ul> | ||
<li>Reduce storage of the database</li> | ||
<li>Optimise all tables except system tables</li> | ||
<li>Simple and efficient way to keep your database clean</li> | ||
<li>Compatible with all platforms</li> | ||
<li>Maintain your database in the best conditions possible</li> | ||
<li>Don't require any dump or backup</li> | ||
<li>Easily run on any server or application</li> | ||
<li>Easy to use</li> | ||
</ul> | ||
|
||
## Supported Databases | ||
|
||
- [x] MySQL | ||
- [x] MariaDB | ||
- [x] PostgreSQL | ||
|
||
## Platforms & Requirements | ||
|
||
<div align="center"> | ||
<img src="https://img.shields.io/badge/OS-MacOS-informational?style=flat&logo=apple&logoColor=white&color=53a863" alt="MacOS" /> | ||
<img src="https://img.shields.io/badge/OS-Linux-informational?style=flat&logo=linux&logoColor=white&color=53a863" alt="Linux" /> | ||
<img src="https://img.shields.io/badge/OS-Windows-informational?style=flat&logo=windows&logoColor=white&color=53a863" alt="Windows" /> | ||
</div> | ||
|
||
<div align="center"> | ||
<img src="https://img.shields.io/badge/Golang-1.16-informational?style=flat&logo=go&logoColor=white&color=53a863" alt="Golang" /> | ||
</div> | ||
|
||
## Installation | ||
|
||
To run the program : | ||
|
||
1. Clone the repository: | ||
|
||
```bash | ||
git clone https://github.com/Maxime-Cllt/GoSqlCleaner.git | ||
``` | ||
|
||
2. Import the libraries: | ||
|
||
```bash | ||
go mod tidy | ||
``` | ||
|
||
3. Compile the program: | ||
|
||
```bash | ||
go build -o GoSqlCleaner | ||
``` | ||
|
||
4. Run the program with the following your database information: | ||
|
||
You need to create a file named `config.json` in the same directory as the program with the following content: | ||
|
||
```json | ||
{ | ||
"driver": "mysql", | ||
"host": "localhost", | ||
"port": "3306", | ||
"username": "root", | ||
"password": "password", | ||
"database": "testdb" | ||
} | ||
``` | ||
|
||
Then run the program with the following command: | ||
|
||
### MacOS & Linux | ||
|
||
```bash | ||
./GoSqlCleaner | ||
``` | ||
|
||
### Windows | ||
|
||
```bash | ||
GoSqlCleaner.exe | ||
``` | ||
|
||
## Notes | ||
|
||
- Time complexity: O(n) where n is the number of tables in the database | ||
- Don't clean triggers, stored procedures, functions, and views | ||
- May not reduce much storage but don't cost much time to run and can be run frequently | ||
- Require some privileges to connect to the database and to perform the cleaning | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package cleaner | ||
|
||
type Cleaner interface { | ||
Clean() bool | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
package mariadb | ||
|
||
import ( | ||
"GoSqlCleaner/database" | ||
"GoSqlCleaner/util" | ||
"database/sql" | ||
"fmt" | ||
"log" | ||
) | ||
|
||
type MariaDbCleaner struct { | ||
database.Database | ||
} | ||
|
||
func (c *MariaDbCleaner) Clean() bool { | ||
|
||
// Connexion à la base de données MySQL | ||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/", c.Username, c.Password, c.Host, c.Port) | ||
|
||
db, err := sql.Open("mysql", dsn) | ||
if err != nil { | ||
log.Fatal("Erreur lors de la connexion à la base de données:", err) | ||
} | ||
defer db.Close() | ||
|
||
err = db.Ping() | ||
if err != nil { | ||
log.Fatal("Impossible de se connecter à la base de données:", err) | ||
} | ||
|
||
totalSize := getTotalSizeSql() | ||
startSize := util.GetDbSize(db, totalSize) | ||
|
||
println("Start size of the database:", util.Green, startSize, " bytes", util.Reset) | ||
|
||
// Set global variables OFF | ||
println("Setting global variables OFF...") | ||
setGlobalVariablesOFF(db) | ||
|
||
// Rebuild index | ||
println("Rebuilding index...") | ||
|
||
// Repair tables | ||
println("Repairing tables...") | ||
repairTables(db) | ||
|
||
// Clean all tables | ||
println("Cleaning all tables...") | ||
cleanAllTables(db) | ||
|
||
// Clear logs | ||
println("Clearing logs...") | ||
clearLogs(db) | ||
|
||
// Set global variables ON | ||
println("Setting global variables ON...") | ||
setGlobalVariablesON(db) | ||
|
||
endSize := util.GetDbSize(db, totalSize) | ||
println("End size of the database:", util.Green, endSize, " bytes", util.Reset) | ||
println("Optimization of ", util.Green, startSize-endSize, util.Reset, " bytes") | ||
|
||
return true | ||
} | ||
|
||
func rebuildIndex(db *sql.DB) { | ||
// Rebuild index | ||
rows, err := db.Query("SELECT CONCAT('ALTER TABLE `', TABLE_SCHEMA, '`.`', TABLE_NAME, '` ENGINE=InnoDB') AS stmt FROM information_schema.TABLES WHERE ENGINE = 'InnoDB' AND TABLE_SCHEMA NOT IN ('sys', 'performance_schema', 'information_schema', 'mysql')") | ||
if err != nil { | ||
log.Fatal("Erreur lors de la récupération des tables:", err) | ||
} | ||
defer rows.Close() | ||
|
||
// iterate over the result | ||
var stmt string | ||
for rows.Next() { | ||
err := rows.Scan(&stmt) | ||
if err != nil { | ||
log.Fatal("Erreur lors de la lecture de la ligne:", err) | ||
} | ||
_, err = db.Exec(stmt) | ||
if err != nil { | ||
log.Fatal("Erreur lors de l'exécution de la requête:", err) | ||
} | ||
} | ||
} | ||
|
||
func repairTables(db *sql.DB) { | ||
// repair tables | ||
rows, err := db.Query("SELECT CONCAT('REPAIR TABLE ',TABLE_SCHEMA, TABLE_NAME, ' EXTENDED') FROM information_schema.TABLES WHERE ENGINE IN ('MyISAM', 'ARCHIVE', 'CSV') AND TABLE_SCHEMA NOT IN ('sys', 'performance_schema', 'information_schema', 'mysql');") | ||
if err != nil { | ||
log.Fatal("Erreur lors de la récupération des tables:", err) | ||
} | ||
defer rows.Close() | ||
|
||
var stmt string | ||
for rows.Next() { | ||
err := rows.Scan(&stmt) | ||
if err != nil { | ||
log.Fatal("Erreur lors de la lecture de la ligne:", err) | ||
} | ||
_, err = db.Exec(stmt) | ||
if err != nil { | ||
log.Fatal("Erreur lors de l'exécution de la requête:", err) | ||
} | ||
} | ||
} | ||
|
||
func cleanAllTables(db *sql.DB) { | ||
// clean all tables | ||
rows, err := db.Query("SELECT CONCAT('`',TABLE_SCHEMA,'`.`', TABLE_NAME, '`') AS stmt FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')") | ||
if err != nil { | ||
log.Fatal("Erreur lors de la récupération des tables:", err) | ||
} | ||
defer rows.Close() | ||
|
||
var stmt string | ||
for rows.Next() { | ||
err := rows.Scan(&stmt) | ||
if err != nil { | ||
log.Fatal("Erreur lors de la lecture de la ligne:", err) | ||
} | ||
_, err = db.Exec("ANALYZE TABLE " + stmt) | ||
if err != nil { | ||
log.Fatal("Erreur lors de l'exécution de la requête:", err) | ||
} | ||
|
||
_, err = db.Exec("OPTIMIZE TABLE " + stmt) | ||
if err != nil { | ||
log.Fatal("Erreur lors de l'exécution de la requête:", err) | ||
} | ||
} | ||
} | ||
|
||
func getTotalSizeSql() string { | ||
return "SELECT SUM(data_length + index_length) AS 'size' FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')" | ||
} | ||
|
||
func clearLogs(db *sql.DB) { | ||
list := []string{ | ||
"FLUSH LOGS", | ||
"PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 30 DAY)", | ||
"FLUSH PRIVILEGES", | ||
"FLUSH TABLES", | ||
"FLUSH TABLES WITH READ LOCK", | ||
"UNLOCK TABLES", | ||
"FLUSH STATUS", | ||
"RESET MASTER", | ||
"RESET SLAVE", | ||
} | ||
|
||
for _, cmd := range list { | ||
_, err := db.Exec(cmd) | ||
if err != nil { | ||
log.Fatal("Erreur lors de l'exécution de la requête:", err) | ||
} | ||
} | ||
} | ||
|
||
func setGlobalVariablesOFF(db *sql.DB) { | ||
globalVariables := []string{ | ||
"SET GLOBAL general_log = 'OFF'", // Disable general log to avoid performance issues during cleaning | ||
"SET GLOBAL slow_query_log = 'OFF'", // Disable slow query log to avoid performance issues during cleaning | ||
"SET GLOBAL log_output = 'TABLE'", // Set log output to table to avoid performance issues during cleaning | ||
"SET GLOBAL log_queries_not_using_indexes = 'ON'", // Enable logging of queries not using indexes | ||
"SET GLOBAL log_slow_admin_statements = 'ON'", // Enable logging of slow admin statements | ||
"SET GLOBAL log_slow_slave_statements = 'ON'", // Enable logging of slow slave statements | ||
} | ||
|
||
for _, cmd := range globalVariables { | ||
_, err := db.Exec(cmd) | ||
if err != nil { | ||
log.Fatal("Erreur lors de l'exécution de la requête:", err) | ||
} | ||
} | ||
} | ||
|
||
func setGlobalVariablesON(db *sql.DB) { | ||
globalVariables := []string{ | ||
"SET GLOBAL general_log = 'ON'", // Enable general log to monitor database activities | ||
"SET GLOBAL slow_query_log = 'ON'", // Enable slow query log to monitor slow queries | ||
"SET GLOBAL log_output = 'FILE'", // Set log output to file to monitor database activities | ||
"SET GLOBAL log_queries_not_using_indexes = 'OFF'", // Disable logging of queries not using indexes | ||
"SET GLOBAL log_slow_admin_statements = 'OFF'", // Disable logging of slow admin statements | ||
"SET GLOBAL log_slow_slave_statements = 'OFF'", // Disable logging of slow slave statements | ||
} | ||
for _, cmd := range globalVariables { | ||
_, err := db.Exec(cmd) | ||
if err != nil { | ||
log.Fatal("Erreur lors de l'exécution de la requête:", err) | ||
} | ||
} | ||
} |
Oops, something went wrong.