sql-optimization
9
总安装量
4
周安装量
#33144
全站排名
安装命令
npx skills add https://github.com/chaterm/terminal-skills --skill sql-optimization
Agent 安装分布
claude-code
4
opencode
3
windsurf
2
codex
2
github-copilot
2
antigravity
2
Skill 文档
SQL ä¼åä¸è°ä¼
æ¦è¿°
æ ¢æ¥è¯¢åæãæ§è¡è®¡åãç´¢å¼ä¼åçéç¨ SQL ä¼åæè½ã
æ§è¡è®¡ååæ
MySQL EXPLAIN
-- åºç¡æ§è¡è®¡å
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
-- è¯¦ç»æ§è¡è®¡å
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
-- JSON æ ¼å¼
EXPLAIN FORMAT=JSON SELECT * FROM users WHERE email = 'test@example.com';
-- å
³é®å段解读
-- type: 访é®ç±»å (system > const > eq_ref > ref > range > index > ALL)
-- key: 使ç¨çç´¢å¼
-- rows: é¢ä¼°æ«æè¡æ°
-- Extra: é¢å¤ä¿¡æ¯ (Using index, Using filesort, Using temporary)
PostgreSQL EXPLAIN
-- åºç¡æ§è¡è®¡å
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
-- å®é
æ§è¡
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
-- 详ç»ä¿¡æ¯
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) SELECT * FROM users WHERE email = 'test@example.com';
-- å
³é®ææ
-- Seq Scan: å
¨è¡¨æ«æ
-- Index Scan: ç´¢å¼æ«æ
-- Bitmap Index Scan: ä½å¾ç´¢å¼æ«æ
-- actual time: å®é
æ§è¡æ¶é´
-- rows: å®é
è¿åè¡æ°
ç´¢å¼ä¼å
ç´¢å¼è®¾è®¡åå
-- 1. éæ©æ§é«çåä¼å
-- éæ©æ§ = ä¸å弿°é / æ»è¡æ°
SELECT COUNT(DISTINCT column) / COUNT(*) AS selectivity FROM table;
-- 2. å¤åç´¢å¼å顺åº
-- éµå¾ªæå·¦åç¼åå
-- å°éæ©æ§é«çåæ¾åé¢
CREATE INDEX idx_user ON users(status, created_at, name);
-- 3. è¦çç´¢å¼
-- ç´¢å¼å
嫿¥è¯¢æéçææå
CREATE INDEX idx_covering ON orders(user_id, status, amount);
SELECT user_id, status, amount FROM orders WHERE user_id = 1;
-- 4. åç¼ç´¢å¼ï¼é¿å符串ï¼
CREATE INDEX idx_email ON users(email(20));
ç´¢å¼ä½¿ç¨æ£æ¥
-- MySQL: æ¥çç´¢å¼ä½¿ç¨æ
åµ
SELECT * FROM sys.schema_index_statistics WHERE table_schema = 'mydb';
-- MySQL: æªä½¿ç¨çç´¢å¼
SELECT * FROM sys.schema_unused_indexes WHERE object_schema = 'mydb';
-- PostgreSQL: ç´¢å¼ä½¿ç¨ç»è®¡
SELECT indexrelname, idx_scan, idx_tup_read, idx_tup_fetch
FROM pg_stat_user_indexes
WHERE schemaname = 'public'
ORDER BY idx_scan;
ç´¢å¼å¤±æåºæ¯
-- 1. 彿°æä½
-- é误
SELECT * FROM users WHERE YEAR(created_at) = 2024;
-- æ£ç¡®
SELECT * FROM users WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';
-- 2. éå¼ç±»å转æ¢
-- é误 (phone æ¯ varchar)
SELECT * FROM users WHERE phone = 13800138000;
-- æ£ç¡®
SELECT * FROM users WHERE phone = '13800138000';
-- 3. LIKE åç¼éé
符
-- é误
SELECT * FROM users WHERE name LIKE '%john%';
-- æ£ç¡®
SELECT * FROM users WHERE name LIKE 'john%';
-- 4. OR æ¡ä»¶
-- å¯è½ä¸èµ°ç´¢å¼
SELECT * FROM users WHERE status = 1 OR name = 'john';
-- æ¹å为 UNION
SELECT * FROM users WHERE status = 1
UNION
SELECT * FROM users WHERE name = 'john';
-- 5. NOT IN / NOT EXISTS
-- å°½éé¿å
ï¼æ¹ç¨ LEFT JOIN
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM orders);
-- æ¹å
SELECT u.* FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE o.id IS NULL;
æ¥è¯¢ä¼å
SELECT ä¼å
-- 1. åªæ¥è¯¢éè¦çå
-- é误
SELECT * FROM users;
-- æ£ç¡®
SELECT id, name, email FROM users;
-- 2. é¿å
SELECT DISTINCTï¼èèæ¯å¦ççéè¦ï¼
-- æ£æ¥æ¯å¦æé夿°æ®çæ ¹æ¬åå
-- 3. ä½¿ç¨ LIMIT
SELECT * FROM logs ORDER BY created_at DESC LIMIT 100;
-- 4. å页ä¼å
-- é误ï¼å¤§åç§»éæ§è½å·®ï¼
SELECT * FROM users LIMIT 10000, 20;
-- æ£ç¡®ï¼ä½¿ç¨æ¸¸æ å页ï¼
SELECT * FROM users WHERE id > 10000 ORDER BY id LIMIT 20;
JOIN ä¼å
-- 1. å°è¡¨é©±å¨å¤§è¡¨
-- ç¡®ä¿ JOIN 顺åºåç
-- 2. ç¡®ä¿ JOIN åæç´¢å¼
SELECT u.name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id -- user_id éè¦ç´¢å¼
WHERE u.status = 1;
-- 3. é¿å
è¿å¤ JOIN
-- è¶
è¿ 3-4 个表ç JOIN èèæåæ¥è¯¢
-- 4. ä½¿ç¨ STRAIGHT_JOIN 强å¶é¡ºåºï¼MySQLï¼
SELECT STRAIGHT_JOIN u.name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id;
åæ¥è¯¢ä¼å
-- 1. å°åæ¥è¯¢æ¹ä¸º JOIN
-- é误
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 100);
-- æ£ç¡®
SELECT DISTINCT u.* FROM users u JOIN orders o ON u.id = o.user_id WHERE o.amount > 100;
-- 2. EXISTS æ¿ä»£ INï¼å¤§æ°æ®éï¼
SELECT * FROM users u WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.amount > 100
);
æ ¢æ¥è¯¢åæ
MySQL æ ¢æ¥è¯¢
-- å¼å¯æ
¢æ¥è¯¢æ¥å¿
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
-- æ¥çé
ç½®
SHOW VARIABLES LIKE 'slow_query%';
SHOW VARIABLES LIKE 'long_query_time';
-- åææ
¢æ¥è¯¢æ¥å¿
-- mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
PostgreSQL æ ¢æ¥è¯¢
-- é
ç½® postgresql.conf
-- log_min_duration_statement = 1000 # è®°å½è¶
è¿1ç§çæ¥è¯¢
-- ä½¿ç¨ pg_stat_statements
CREATE EXTENSION pg_stat_statements;
SELECT query, calls, total_time, mean_time, rows
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 10;
常è§åºæ¯
åºæ¯ 1ï¼å¤§è¡¨å页
-- 使ç¨å»¶è¿å
³è
SELECT u.* FROM users u
JOIN (SELECT id FROM users ORDER BY created_at DESC LIMIT 10000, 20) t
ON u.id = t.id;
-- ä½¿ç¨æ¸¸æ å页
SELECT * FROM users
WHERE id > last_seen_id
ORDER BY id
LIMIT 20;
åºæ¯ 2ï¼æ¹éæ´æ°
-- åæ¹æ´æ°ï¼é¿å
é¿äºå¡
-- æ¯æ¬¡æ´æ° 1000 æ¡
UPDATE users SET status = 1 WHERE id BETWEEN 1 AND 1000;
UPDATE users SET status = 1 WHERE id BETWEEN 1001 AND 2000;
-- ...
-- æä½¿ç¨åå¨è¿ç¨å¾ªç¯
åºæ¯ 3ï¼ç»è®¡æ¥è¯¢ä¼å
-- ä½¿ç¨æ±æ»è¡¨
CREATE TABLE daily_stats (
date DATE PRIMARY KEY,
total_orders INT,
total_amount DECIMAL(10,2)
);
-- 宿¶ä»»å¡æ´æ°æ±æ»è¡¨
INSERT INTO daily_stats
SELECT DATE(created_at), COUNT(*), SUM(amount)
FROM orders
WHERE DATE(created_at) = CURDATE() - INTERVAL 1 DAY
GROUP BY DATE(created_at)
ON DUPLICATE KEY UPDATE
total_orders = VALUES(total_orders),
total_amount = VALUES(total_amount);
åºæ¯ 4ï¼éä¼å
-- åå°éèå´
-- é误ï¼é宿´ä¸ªè¡¨
SELECT * FROM users FOR UPDATE;
-- æ£ç¡®ï¼åªéå®éè¦çè¡
SELECT * FROM users WHERE id = 1 FOR UPDATE;
-- 使ç¨ä¹è§é
UPDATE users SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = 5;
ä¼åæ£æ¥æ¸ å
| æ£æ¥é¡¹ | 说æ |
|---|---|
| æ§è¡è®¡å | æ¯å¦å ¨è¡¨æ«æãæ¯å¦ä½¿ç¨ç´¢å¼ |
| ç´¢å¼è®¾è®¡ | éæ©æ§ãè¦çç´¢å¼ãå¤åç´¢å¼é¡ºåº |
| æ¥è¯¢æ¹å | é¿å SELECT *ãä¼ååæ¥è¯¢ |
| å页æ¹å¼ | 大åç§»éä½¿ç¨æ¸¸æ å页 |
| æ¹éæä½ | åæ¹å¤çãé¿å é¿äºå¡ |
| éç²åº¦ | åå°éèå´ã使ç¨ä¹è§é |