| name | db |
| description | Full database skill — MySQL, PostgreSQL, MongoDB, Redis, ScyllaDB, Meilisearch — setup, queries, optimization, backups, debugging |
| version | 1.0.0 |
| author | veekunth217 |
| tags | ["mysql","postgresql","mongodb","redis","scylladb","meilisearch","database","optimization","backup","slow-query"] |
| platforms | ["claude-code","cursor","codex"] |
Database Skill
Full-stack database expertise — relational, document, wide-column, cache, and search. From initial setup to production tuning.
RULE: Show all schema changes, config changes, and migrations before applying. Wait for GO.
MySQL — Setup & Optimization
Installation (Ubuntu)
apt-get install -y mysql-server
mysql_secure_installation
Key tuning (my.cnf)
[mysqld]
innodb_buffer_pool_size = 1G
innodb_buffer_pool_instances = 4
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
query_cache_type = 0
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
max_connections = 200
Common operations
SHOW PROCESSLIST;
SHOW FULL PROCESSLIST;
EXPLAIN SELECT * FROM orders WHERE user_id = 123;
EXPLAIN ANALYZE SELECT ...;
SHOW INDEX FROM table_name;
ALTER TABLE orders ADD INDEX idx_user_created (user_id, created_at);
mysqldump -u root -p
PostgreSQL — Setup & Optimization
Installation (Ubuntu)
apt-get install -y postgresql postgresql-contrib
sudo -u postgres psql
Key tuning (postgresql.conf)
shared_buffers = 256MB
effective_cache_size = 1GB
work_mem = 16MB
maintenance_work_mem = 256MB
wal_buffers = 16MB
checkpoint_completion_target = 0.9
random_page_cost = 1.1
effective_io_concurrency = 200
max_connections = 100
shared_preload_libraries = 'pg_stat_statements'
pg_stat_statements (slow query analysis)
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
SELECT query, calls, mean_exec_time, total_exec_time
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;
Common operations
\l
\dt
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE user_id = $1;
CREATE INDEX CONCURRENTLY idx_orders_user ON orders(user_id);
CREATE INDEX idx_gin ON posts USING gin(to_tsvector('english', content));
pg_dump -U postgres -Fc mydb > mydb.dump
pg_restore -U postgres -d mydb mydb.dump
MongoDB — Setup & Configuration
Installation (Ubuntu)
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | gpg -o /usr/share/keyrings/mongodb.gpg --dearmor
echo "deb [ signed-by=/usr/share/keyrings/mongodb.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" > /etc/apt/sources.list.d/mongodb-org-7.0.list
apt-get update && apt-get install -y mongodb-org
systemctl enable --now mongod
mongod.conf (production)
storage:
dbPath: /var/lib/mongodb
wiredTiger:
engineConfig:
cacheSizeGB: 1
net:
bindIp: 127.0.0.1
port: 27017
security:
authorization: enabled
operationProfiling:
slowOpThresholdMs: 100
mode: slowOp
Common operations
db.orders.find({ userId: ObjectId("...") }).explain("executionStats")
db.orders.createIndex({ userId: 1, createdAt: -1 })
db.products.createIndex({ name: "text", description: "text" })
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$userId", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } },
{ $limit: 10 }
])
mongodump --db mydb --out /backup/$(date +%Y%m%d)
mongorestore --db mydb /backup/20260504/mydb
Redis — Setup & Configuration
Installation (Ubuntu)
apt-get install -y redis-server
redis.conf (production)
bind 127.0.0.1
port 6379
requirepass [strong-password]
maxmemory 512mb
maxmemory-policy allkeys-lru # for pure cache
# maxmemory-policy volatile-lru # if mixing cache + persistent keys
appendonly no # disable for pure cache use
save "" # disable RDB for pure cache
# For session/persistent use — enable persistence:
# appendonly yes
# appendfsync everysec
Patterns
redis-cli MONITOR
redis-cli --memkeys
redis-cli INFO memory
redis-cli FLUSHDB
redis-cli FLUSHALL
ScyllaDB — Setup & Configuration
Installation (Ubuntu/Docker)
docker run -d --name scylla \
-p 9042:9042 \
-v scylla-data:/var/lib/scylla \
scylladb/scylla:5.4 \
--smp 2 --memory 2G --overprovisioned 1
docker exec -it scylla nodetool status
scylla.yaml (production key settings)
cluster_name: 'my-cluster'
num_tokens: 256
authenticator: PasswordAuthenticator
authorizer: CassandraAuthorizer
commitlog_sync: periodic
commitlog_sync_period_in_ms: 10000
compaction_throughput_mb_per_sec: 16
read_request_timeout_in_ms: 5000
write_request_timeout_in_ms: 2000
Schema design (access-pattern-first)
CREATE KEYSPACE myapp
WITH replication = {'class': 'NetworkTopologyStrategy', 'datacenter1': 3}
AND durable_writes = true;
CREATE TABLE messages_by_room (
room_id UUID,
sent_at TIMESTAMP,
msg_id UUID,
sender_id UUID,
body TEXT,
PRIMARY KEY ((room_id), sent_at, msg_id)
) WITH CLUSTERING ORDER BY (sent_at DESC)
AND default_time_to_live = 2592000;
Meilisearch — Setup & Configuration
Installation
docker run -d --name meilisearch \
-p 7700:7700 \
-v meilisearch-data:/meili_data \
-e MEILI_MASTER_KEY='[strong-key]' \
-e MEILI_ENV=production \
getmeili/meilisearch:v1.8
curl -L https://install.meilisearch.com | sh
./meilisearch --master-key '[key]' --env production
config.toml (production)
env = "production"
master_key = "[strong-master-key]"
db_path = "/var/lib/meilisearch/data"
dump_dir = "/var/lib/meilisearch/dumps"
snapshot_dir = "/var/lib/meilisearch/snapshots"
http_addr = "127.0.0.1:7700"
log_level = "WARN"
max_indexing_memory = "512 MiB"
Nginx reverse proxy for Meilisearch
location /search/ {
proxy_pass http://127.0.0.1:7700/;
proxy_set_header Host $host;
# Only expose search endpoint, not admin
limit_except GET { deny all; }
}
Index setup & search (Node.js SDK)
import { MeiliSearch } from 'meilisearch'
const client = new MeiliSearch({
host: 'http://127.0.0.1:7700',
apiKey: process.env.MEILI_MASTER_KEY,
})
await client.createIndex('products', { primaryKey: 'id' })
await client.index('products').updateSettings({
searchableAttributes: ['name', 'description', 'tags'],
filterableAttributes: ['category', 'price', 'in_stock'],
sortableAttributes: ['price', 'created_at'],
rankingRules: ['words', 'typo', 'proximity', 'attribute', 'sort', 'exactness'],
})
await client.index('products').addDocuments(products)
const results = await client.index('products').search('wireless headphones', {
filter: ['category = "electronics"', 'price < 100', 'in_stock = true'],
sort: ['price:asc'],
limit: 20,
offset: 0,
attributesToHighlight: ['name', 'description'],
})
Sync from primary DB (PostgreSQL → Meilisearch)
async function syncToMeilisearch() {
const products = await db.select().from(productsTable)
.where(gt(productsTable.updatedAt, lastSyncAt))
if (products.length === 0) return
await client.index('products').addDocuments(products, { primaryKey: 'id' })
await updateLastSyncTimestamp()
}
Backup Strategies
| Database | Backup command | Restore |
|---|
| MySQL | mysqldump --single-transaction mydb > db.sql | mysql mydb < db.sql |
| PostgreSQL | pg_dump -Fc mydb > db.dump | pg_restore -d mydb db.dump |
| MongoDB | mongodump --db mydb --out /backup/ | mongorestore /backup/mydb/ |
| Redis | redis-cli BGSAVE → copy /var/lib/redis/dump.rdb | Copy back + restart |
| ScyllaDB | nodetool snapshot myks | sstableloader |
| Meilisearch | curl -X POST 'http://localhost:7700/dumps' | Restart with dump |
Slow Query Debugging
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 0.5;
SHOW VARIABLES LIKE 'slow_query_log_file';
SELECT query, calls, mean_exec_time FROM pg_stat_statements
ORDER BY mean_exec_time DESC LIMIT 10;
db.setProfilingLevel(1, { slowms: 100 })
db.system.profile.find().sort({ ts: -1 }).limit(10)
redis-cli SLOWLOG GET 10
redis-cli SLOWLOG RESET