[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CD3CPN5A14C7R9VXFM9X4H":3,"skill-same:01M6CD3CPN5A14C7R9VXFM9X4H":84},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":52,"linkOnly":53,"markdownContent":54,"markdownBody":55,"frontMatter":56,"refName":58,"commitSha":59,"skillDirectory":60,"forksCount":61,"repositoryHtmlUrl":62,"repositoryHomepageUrl":6,"ownerHtmlUrl":63,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":64,"install":65,"resources":77},"01M6CD3CPN5A14C7R9VXFM9X4H","sql-optimization-patterns",null,"Master SQL query optimization, indexing strategies, and EXPLAIN analysis to dramatically improve database performance and eliminate slow queries. Use when debugging slow queries, designing database schemas, or optimizing application performance.","cercova-studios\u002F10x-swe","cercova-studios","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F217108198?v=4","01M6CCYGHXTH80N3BXRW6KESTE","Cercova Studios","01M6CCYGPADH5MJDR0VNNR775C",1,"MIT","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fsql-optimization-patterns\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51],"sql optimization patterns","sql","sql optimization","Optimization","patterns","indexing","strategies","sql query optimization","query","sql query","when","query optimization","master","database performance","queries","explain","analysis","debugging","database","use","Designing Database Schemas","improve","performance","2026-11-10 10:12:30",false,"---\nname: sql-optimization-patterns\ndescription: Master SQL query optimization, indexing strategies, and EXPLAIN analysis to dramatically improve database performance and eliminate slow queries. Use when debugging slow queries, designing database schemas, or optimizing application performance.\ndisable-model-invocation: true\n---\n\n# SQL Optimization Patterns\n\nTransform slow database queries into lightning-fast operations through systematic optimization, proper indexing, and query plan analysis.\n\n## When to Use This Skill\n\n- Debugging slow-running queries\n- Designing performant database schemas\n- Optimizing application response times\n- Reducing database load and costs\n- Improving scalability for growing datasets\n- Analyzing EXPLAIN query plans\n- Implementing efficient indexes\n- Resolving N+1 query problems\n\n## Core Concepts\n\n### 1. Query Execution Plans (EXPLAIN)\n\nUnderstanding EXPLAIN output is fundamental to optimization.\n\n**PostgreSQL EXPLAIN:**\n\n```sql\n-- Basic explain\nEXPLAIN SELECT * FROM users WHERE email = 'user@example.com';\n\n-- With actual execution stats\nEXPLAIN ANALYZE\nSELECT * FROM users WHERE email = 'user@example.com';\n\n-- Verbose output with more details\nEXPLAIN (ANALYZE, BUFFERS, VERBOSE)\nSELECT u.*, o.order_total\nFROM users u\nJOIN orders o ON u.id = o.user_id\nWHERE u.created_at > NOW() - INTERVAL '30 days';\n```\n\n**Key Metrics to Watch:**\n\n- **Seq Scan**: Full table scan (usually slow for large tables)\n- **Index Scan**: Using index (good)\n- **Index Only Scan**: Using index without touching table (best)\n- **Nested Loop**: Join method (okay for small datasets)\n- **Hash Join**: Join method (good for larger datasets)\n- **Merge Join**: Join method (good for sorted data)\n- **Cost**: Estimated query cost (lower is better)\n- **Rows**: Estimated rows returned\n- **Actual Time**: Real execution time\n\n### 2. Index Strategies\n\nIndexes are the most powerful optimization tool.\n\n**Index Types:**\n\n- **B-Tree**: Default, good for equality and range queries\n- **Hash**: Only for equality (=) comparisons\n- **GIN**: Full-text search, array queries, JSONB\n- **GiST**: Geometric data, full-text search\n- **BRIN**: Block Range INdex for very large tables with correlation\n\n```sql\n-- Standard B-Tree index\nCREATE INDEX idx_users_email ON users(email);\n\n-- Composite index (order matters!)\nCREATE INDEX idx_orders_user_status ON orders(user_id, status);\n\n-- Partial index (index subset of rows)\nCREATE INDEX idx_active_users ON users(email)\nWHERE status = 'active';\n\n-- Expression index\nCREATE INDEX idx_users_lower_email ON users(LOWER(email));\n\n-- Covering index (include additional columns)\nCREATE INDEX idx_users_email_covering ON users(email)\nINCLUDE (name, created_at);\n\n-- Full-text search index\nCREATE INDEX idx_posts_search ON posts\nUSING GIN(to_tsvector('english', title || ' ' || body));\n\n-- JSONB index\nCREATE INDEX idx_metadata ON events USING GIN(metadata);\n```\n\n### 3. Query Optimization Patterns\n\n**Avoid SELECT \\*:**\n\n```sql\n-- Bad: Fetches unnecessary columns\nSELECT * FROM users WHERE id = 123;\n\n-- Good: Fetch only what you need\nSELECT id, email, name FROM users WHERE id = 123;\n```\n\n**Use WHERE Clause Efficiently:**\n\n```sql\n-- Bad: Function prevents index usage\nSELECT * FROM users WHERE LOWER(email) = 'user@example.com';\n\n-- Good: Create functional index or use exact match\nCREATE INDEX idx_users_email_lower ON users(LOWER(email));\n-- Then:\nSELECT * FROM users WHERE LOWER(email) = 'user@example.com';\n\n-- Or store normalized data\nSELECT * FROM users WHERE email = 'user@example.com';\n```\n\n**Optimize JOINs:**\n\n```sql\n-- Bad: Cartesian product then filter\nSELECT u.name, o.total\nFROM users u, orders o\nWHERE u.id = o.user_id AND u.created_at > '2024-01-01';\n\n-- Good: Filter before join\nSELECT u.name, o.total\nFROM users u\nJOIN orders o ON u.id = o.user_id\nWHERE u.created_at > '2024-01-01';\n\n-- Better: Filter both tables\nSELECT u.name, o.total\nFROM (SELECT * FROM users WHERE created_at > '2024-01-01') u\nJOIN orders o ON u.id = o.user_id;\n```\n\n## Optimization Patterns\n\n### Pattern 1: Eliminate N+1 Queries\n\n**Problem: N+1 Query Anti-Pattern**\n\n```python\n# Bad: Executes N+1 queries\nusers = db.query(\"SELECT * FROM users LIMIT 10\")\nfor user in users:\n    orders = db.query(\"SELECT * FROM orders WHERE user_id = ?\", user.id)\n    # Process orders\n```\n\n**Solution: Use JOINs or Batch Loading**\n\n```sql\n-- Solution 1: JOIN\nSELECT\n    u.id, u.name,\n    o.id as order_id, o.total\nFROM users u\nLEFT JOIN orders o ON u.id = o.user_id\nWHERE u.id IN (1, 2, 3, 4, 5);\n\n-- Solution 2: Batch query\nSELECT * FROM orders\nWHERE user_id IN (1, 2, 3, 4, 5);\n```\n\n```python\n# Good: Single query with JOIN or batch load\n# Using JOIN\nresults = db.query(\"\"\"\n    SELECT u.id, u.name, o.id as order_id, o.total\n    FROM users u\n    LEFT JOIN orders o ON u.id = o.user_id\n    WHERE u.id IN (1, 2, 3, 4, 5)\n\"\"\")\n\n# Or batch load\nusers = db.query(\"SELECT * FROM users LIMIT 10\")\nuser_ids = [u.id for u in users]\norders = db.query(\n    \"SELECT * FROM orders WHERE user_id IN (?)\",\n    user_ids\n)\n# Group orders by user_id\norders_by_user = {}\nfor order in orders:\n    orders_by_user.setdefault(order.user_id, []).append(order)\n```\n\n### Pattern 2: Optimize Pagination\n\n**Bad: OFFSET on Large Tables**\n\n```sql\n-- Slow for large offsets\nSELECT * FROM users\nORDER BY created_at DESC\nLIMIT 20 OFFSET 100000;  -- Very slow!\n```\n\n**Good: Cursor-Based Pagination**\n\n```sql\n-- Much faster: Use cursor (last seen ID)\nSELECT * FROM users\nWHERE created_at \u003C '2024-01-15 10:30:00'  -- Last cursor\nORDER BY created_at DESC\nLIMIT 20;\n\n-- With composite sorting\nSELECT * FROM users\nWHERE (created_at, id) \u003C ('2024-01-15 10:30:00', 12345)\nORDER BY created_at DESC, id DESC\nLIMIT 20;\n\n-- Requires index\nCREATE INDEX idx_users_cursor ON users(created_at DESC, id DESC);\n```\n\n### Pattern 3: Aggregate Efficiently\n\n**Optimize COUNT Queries:**\n\n```sql\n-- Bad: Counts all rows\nSELECT COUNT(*) FROM orders;  -- Slow on large tables\n\n-- Good: Use estimates for approximate counts\nSELECT reltuples::bigint AS estimate\nFROM pg_class\nWHERE relname = 'orders';\n\n-- Good: Filter before counting\nSELECT COUNT(*) FROM orders\nWHERE created_at > NOW() - INTERVAL '7 days';\n\n-- Better: Use index-only scan\nCREATE INDEX idx_orders_created ON orders(created_at);\nSELECT COUNT(*) FROM orders\nWHERE created_at > NOW() - INTERVAL '7 days';\n```\n\n**Optimize GROUP BY:**\n\n```sql\n-- Bad: Group by then filter\nSELECT user_id, COUNT(*) as order_count\nFROM orders\nGROUP BY user_id\nHAVING COUNT(*) > 10;\n\n-- Better: Filter first, then group (if possible)\nSELECT user_id, COUNT(*) as order_count\nFROM orders\nWHERE status = 'completed'\nGROUP BY user_id\nHAVING COUNT(*) > 10;\n\n-- Best: Use covering index\nCREATE INDEX idx_orders_user_status ON orders(user_id, status);\n```\n\n### Pattern 4: Subquery Optimization\n\n**Transform Correlated Subqueries:**\n\n```sql\n-- Bad: Correlated subquery (runs for each row)\nSELECT u.name, u.email,\n    (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) as order_count\nFROM users u;\n\n-- Good: JOIN with aggregation\nSELECT u.name, u.email, COUNT(o.id) as order_count\nFROM users u\nLEFT JOIN orders o ON o.user_id = u.id\nGROUP BY u.id, u.name, u.email;\n\n-- Better: Use window functions\nSELECT DISTINCT ON (u.id)\n    u.name, u.email,\n    COUNT(o.id) OVER (PARTITION BY u.id) as order_count\nFROM users u\nLEFT JOIN orders o ON o.user_id = u.id;\n```\n\n**Use CTEs for Clarity:**\n\n```sql\n-- Using Common Table Expressions\nWITH recent_users AS (\n    SELECT id, name, email\n    FROM users\n    WHERE created_at > NOW() - INTERVAL '30 days'\n),\nuser_order_counts AS (\n    SELECT user_id, COUNT(*) as order_count\n    FROM orders\n    WHERE created_at > NOW() - INTERVAL '30 days'\n    GROUP BY user_id\n)\nSELECT ru.name, ru.email, COALESCE(uoc.order_count, 0) as orders\nFROM recent_users ru\nLEFT JOIN user_order_counts uoc ON ru.id = uoc.user_id;\n```\n\n### Pattern 5: Batch Operations\n\n**Batch INSERT:**\n\n```sql\n-- Bad: Multiple individual inserts\nINSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');\nINSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');\nINSERT INTO users (name, email) VALUES ('Carol', 'carol@example.com');\n\n-- Good: Batch insert\nINSERT INTO users (name, email) VALUES\n    ('Alice', 'alice@example.com'),\n    ('Bob', 'bob@example.com'),\n    ('Carol', 'carol@example.com');\n\n-- Better: Use COPY for bulk inserts (PostgreSQL)\nCOPY users (name, email) FROM '\u002Ftmp\u002Fusers.csv' CSV HEADER;\n```\n\n**Batch UPDATE:**\n\n```sql\n-- Bad: Update in loop\nUPDATE users SET status = 'active' WHERE id = 1;\nUPDATE users SET status = 'active' WHERE id = 2;\n-- ... repeat for many IDs\n\n-- Good: Single UPDATE with IN clause\nUPDATE users\nSET status = 'active'\nWHERE id IN (1, 2, 3, 4, 5, ...);\n\n-- Better: Use temporary table for large batches\nCREATE TEMP TABLE temp_user_updates (id INT, new_status VARCHAR);\nINSERT INTO temp_user_updates VALUES (1, 'active'), (2, 'active'), ...;\n\nUPDATE users u\nSET status = t.new_status\nFROM temp_user_updates t\nWHERE u.id = t.id;\n```\n\n## Advanced Techniques\n\n### Materialized Views\n\nPre-compute expensive queries.\n\n```sql\n-- Create materialized view\nCREATE MATERIALIZED VIEW user_order_summary AS\nSELECT\n    u.id,\n    u.name,\n    COUNT(o.id) as total_orders,\n    SUM(o.total) as total_spent,\n    MAX(o.created_at) as last_order_date\nFROM users u\nLEFT JOIN orders o ON u.id = o.user_id\nGROUP BY u.id, u.name;\n\n-- Add index to materialized view\nCREATE INDEX idx_user_summary_spent ON user_order_summary(total_spent DESC);\n\n-- Refresh materialized view\nREFRESH MATERIALIZED VIEW user_order_summary;\n\n-- Concurrent refresh (PostgreSQL)\nREFRESH MATERIALIZED VIEW CONCURRENTLY user_order_summary;\n\n-- Query materialized view (very fast)\nSELECT * FROM user_order_summary\nWHERE total_spent > 1000\nORDER BY total_spent DESC;\n```\n\n### Partitioning\n\nSplit large tables for better performance.\n\n```sql\n-- Range partitioning by date (PostgreSQL)\nCREATE TABLE orders (\n    id SERIAL,\n    user_id INT,\n    total DECIMAL,\n    created_at TIMESTAMP\n) PARTITION BY RANGE (created_at);\n\n-- Create partitions\nCREATE TABLE orders_2024_q1 PARTITION OF orders\n    FOR VALUES FROM ('2024-01-01') TO ('2024-04-01');\n\nCREATE TABLE orders_2024_q2 PARTITION OF orders\n    FOR VALUES FROM ('2024-04-01') TO ('2024-07-01');\n\n-- Queries automatically use appropriate partition\nSELECT * FROM orders\nWHERE created_at BETWEEN '2024-02-01' AND '2024-02-28';\n-- Only scans orders_2024_q1 partition\n```\n\n### Query Hints and Optimization\n\n```sql\n-- Force index usage (MySQL)\nSELECT * FROM users\nUSE INDEX (idx_users_email)\nWHERE email = 'user@example.com';\n\n-- Parallel query (PostgreSQL)\nSET max_parallel_workers_per_gather = 4;\nSELECT * FROM large_table WHERE condition;\n\n-- Join hints (PostgreSQL)\nSET enable_nestloop = OFF;  -- Force hash or merge join\n```\n\n## Best Practices\n\n1. **Index Selectively**: Too many indexes slow down writes\n2. **Monitor Query Performance**: Use slow query logs\n3. **Keep Statistics Updated**: Run ANALYZE regularly\n4. **Use Appropriate Data Types**: Smaller types = better performance\n5. **Normalize Thoughtfully**: Balance normalization vs performance\n6. **Cache Frequently Accessed Data**: Use application-level caching\n7. **Connection Pooling**: Reuse database connections\n8. **Regular Maintenance**: VACUUM, ANALYZE, rebuild indexes\n\n```sql\n-- Update statistics\nANALYZE users;\nANALYZE VERBOSE orders;\n\n-- Vacuum (PostgreSQL)\nVACUUM ANALYZE users;\nVACUUM FULL users;  -- Reclaim space (locks table)\n\n-- Reindex\nREINDEX INDEX idx_users_email;\nREINDEX TABLE users;\n```\n\n## Common Pitfalls\n\n- **Over-Indexing**: Each index slows down INSERT\u002FUPDATE\u002FDELETE\n- **Unused Indexes**: Waste space and slow writes\n- **Missing Indexes**: Slow queries, full table scans\n- **Implicit Type Conversion**: Prevents index usage\n- **OR Conditions**: Can't use indexes efficiently\n- **LIKE with Leading Wildcard**: `LIKE '%abc'` can't use index\n- **Function in WHERE**: Prevents index usage unless functional index exists\n\n## Monitoring Queries\n\n```sql\n-- Find slow queries (PostgreSQL)\nSELECT query, calls, total_time, mean_time\nFROM pg_stat_statements\nORDER BY mean_time DESC\nLIMIT 10;\n\n-- Find missing indexes (PostgreSQL)\nSELECT\n    schemaname,\n    tablename,\n    seq_scan,\n    seq_tup_read,\n    idx_scan,\n    seq_tup_read \u002F seq_scan AS avg_seq_tup_read\nFROM pg_stat_user_tables\nWHERE seq_scan > 0\nORDER BY seq_tup_read DESC\nLIMIT 10;\n\n-- Find unused indexes (PostgreSQL)\nSELECT\n    schemaname,\n    tablename,\n    indexname,\n    idx_scan,\n    idx_tup_read,\n    idx_tup_fetch\nFROM pg_stat_user_indexes\nWHERE idx_scan = 0\nORDER BY pg_relation_size(indexrelid) DESC;\n```\n","# SQL Optimization Patterns\n\nTransform slow database queries into lightning-fast operations through systematic optimization, proper indexing, and query plan analysis.\n\n## When to Use This Skill\n\n- Debugging slow-running queries\n- Designing performant database schemas\n- Optimizing application response times\n- Reducing database load and costs\n- Improving scalability for growing datasets\n- Analyzing EXPLAIN query plans\n- Implementing efficient indexes\n- Resolving N+1 query problems\n\n## Core Concepts\n\n### 1. Query Execution Plans (EXPLAIN)\n\nUnderstanding EXPLAIN output is fundamental to optimization.\n\n**PostgreSQL EXPLAIN:**\n\n```sql\n-- Basic explain\nEXPLAIN SELECT * FROM users WHERE email = 'user@example.com';\n\n-- With actual execution stats\nEXPLAIN ANALYZE\nSELECT * FROM users WHERE email = 'user@example.com';\n\n-- Verbose output with more details\nEXPLAIN (ANALYZE, BUFFERS, VERBOSE)\nSELECT u.*, o.order_total\nFROM users u\nJOIN orders o ON u.id = o.user_id\nWHERE u.created_at > NOW() - INTERVAL '30 days';\n```\n\n**Key Metrics to Watch:**\n\n- **Seq Scan**: Full table scan (usually slow for large tables)\n- **Index Scan**: Using index (good)\n- **Index Only Scan**: Using index without touching table (best)\n- **Nested Loop**: Join method (okay for small datasets)\n- **Hash Join**: Join method (good for larger datasets)\n- **Merge Join**: Join method (good for sorted data)\n- **Cost**: Estimated query cost (lower is better)\n- **Rows**: Estimated rows returned\n- **Actual Time**: Real execution time\n\n### 2. Index Strategies\n\nIndexes are the most powerful optimization tool.\n\n**Index Types:**\n\n- **B-Tree**: Default, good for equality and range queries\n- **Hash**: Only for equality (=) comparisons\n- **GIN**: Full-text search, array queries, JSONB\n- **GiST**: Geometric data, full-text search\n- **BRIN**: Block Range INdex for very large tables with correlation\n\n```sql\n-- Standard B-Tree index\nCREATE INDEX idx_users_email ON users(email);\n\n-- Composite index (order matters!)\nCREATE INDEX idx_orders_user_status ON orders(user_id, status);\n\n-- Partial index (index subset of rows)\nCREATE INDEX idx_active_users ON users(email)\nWHERE status = 'active';\n\n-- Expression index\nCREATE INDEX idx_users_lower_email ON users(LOWER(email));\n\n-- Covering index (include additional columns)\nCREATE INDEX idx_users_email_covering ON users(email)\nINCLUDE (name, created_at);\n\n-- Full-text search index\nCREATE INDEX idx_posts_search ON posts\nUSING GIN(to_tsvector('english', title || ' ' || body));\n\n-- JSONB index\nCREATE INDEX idx_metadata ON events USING GIN(metadata);\n```\n\n### 3. Query Optimization Patterns\n\n**Avoid SELECT \\*:**\n\n```sql\n-- Bad: Fetches unnecessary columns\nSELECT * FROM users WHERE id = 123;\n\n-- Good: Fetch only what you need\nSELECT id, email, name FROM users WHERE id = 123;\n```\n\n**Use WHERE Clause Efficiently:**\n\n```sql\n-- Bad: Function prevents index usage\nSELECT * FROM users WHERE LOWER(email) = 'user@example.com';\n\n-- Good: Create functional index or use exact match\nCREATE INDEX idx_users_email_lower ON users(LOWER(email));\n-- Then:\nSELECT * FROM users WHERE LOWER(email) = 'user@example.com';\n\n-- Or store normalized data\nSELECT * FROM users WHERE email = 'user@example.com';\n```\n\n**Optimize JOINs:**\n\n```sql\n-- Bad: Cartesian product then filter\nSELECT u.name, o.total\nFROM users u, orders o\nWHERE u.id = o.user_id AND u.created_at > '2024-01-01';\n\n-- Good: Filter before join\nSELECT u.name, o.total\nFROM users u\nJOIN orders o ON u.id = o.user_id\nWHERE u.created_at > '2024-01-01';\n\n-- Better: Filter both tables\nSELECT u.name, o.total\nFROM (SELECT * FROM users WHERE created_at > '2024-01-01') u\nJOIN orders o ON u.id = o.user_id;\n```\n\n## Optimization Patterns\n\n### Pattern 1: Eliminate N+1 Queries\n\n**Problem: N+1 Query Anti-Pattern**\n\n```python\n# Bad: Executes N+1 queries\nusers = db.query(\"SELECT * FROM users LIMIT 10\")\nfor user in users:\n    orders = db.query(\"SELECT * FROM orders WHERE user_id = ?\", user.id)\n    # Process orders\n```\n\n**Solution: Use JOINs or Batch Loading**\n\n```sql\n-- Solution 1: JOIN\nSELECT\n    u.id, u.name,\n    o.id as order_id, o.total\nFROM users u\nLEFT JOIN orders o ON u.id = o.user_id\nWHERE u.id IN (1, 2, 3, 4, 5);\n\n-- Solution 2: Batch query\nSELECT * FROM orders\nWHERE user_id IN (1, 2, 3, 4, 5);\n```\n\n```python\n# Good: Single query with JOIN or batch load\n# Using JOIN\nresults = db.query(\"\"\"\n    SELECT u.id, u.name, o.id as order_id, o.total\n    FROM users u\n    LEFT JOIN orders o ON u.id = o.user_id\n    WHERE u.id IN (1, 2, 3, 4, 5)\n\"\"\")\n\n# Or batch load\nusers = db.query(\"SELECT * FROM users LIMIT 10\")\nuser_ids = [u.id for u in users]\norders = db.query(\n    \"SELECT * FROM orders WHERE user_id IN (?)\",\n    user_ids\n)\n# Group orders by user_id\norders_by_user = {}\nfor order in orders:\n    orders_by_user.setdefault(order.user_id, []).append(order)\n```\n\n### Pattern 2: Optimize Pagination\n\n**Bad: OFFSET on Large Tables**\n\n```sql\n-- Slow for large offsets\nSELECT * FROM users\nORDER BY created_at DESC\nLIMIT 20 OFFSET 100000;  -- Very slow!\n```\n\n**Good: Cursor-Based Pagination**\n\n```sql\n-- Much faster: Use cursor (last seen ID)\nSELECT * FROM users\nWHERE created_at \u003C '2024-01-15 10:30:00'  -- Last cursor\nORDER BY created_at DESC\nLIMIT 20;\n\n-- With composite sorting\nSELECT * FROM users\nWHERE (created_at, id) \u003C ('2024-01-15 10:30:00', 12345)\nORDER BY created_at DESC, id DESC\nLIMIT 20;\n\n-- Requires index\nCREATE INDEX idx_users_cursor ON users(created_at DESC, id DESC);\n```\n\n### Pattern 3: Aggregate Efficiently\n\n**Optimize COUNT Queries:**\n\n```sql\n-- Bad: Counts all rows\nSELECT COUNT(*) FROM orders;  -- Slow on large tables\n\n-- Good: Use estimates for approximate counts\nSELECT reltuples::bigint AS estimate\nFROM pg_class\nWHERE relname = 'orders';\n\n-- Good: Filter before counting\nSELECT COUNT(*) FROM orders\nWHERE created_at > NOW() - INTERVAL '7 days';\n\n-- Better: Use index-only scan\nCREATE INDEX idx_orders_created ON orders(created_at);\nSELECT COUNT(*) FROM orders\nWHERE created_at > NOW() - INTERVAL '7 days';\n```\n\n**Optimize GROUP BY:**\n\n```sql\n-- Bad: Group by then filter\nSELECT user_id, COUNT(*) as order_count\nFROM orders\nGROUP BY user_id\nHAVING COUNT(*) > 10;\n\n-- Better: Filter first, then group (if possible)\nSELECT user_id, COUNT(*) as order_count\nFROM orders\nWHERE status = 'completed'\nGROUP BY user_id\nHAVING COUNT(*) > 10;\n\n-- Best: Use covering index\nCREATE INDEX idx_orders_user_status ON orders(user_id, status);\n```\n\n### Pattern 4: Subquery Optimization\n\n**Transform Correlated Subqueries:**\n\n```sql\n-- Bad: Correlated subquery (runs for each row)\nSELECT u.name, u.email,\n    (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) as order_count\nFROM users u;\n\n-- Good: JOIN with aggregation\nSELECT u.name, u.email, COUNT(o.id) as order_count\nFROM users u\nLEFT JOIN orders o ON o.user_id = u.id\nGROUP BY u.id, u.name, u.email;\n\n-- Better: Use window functions\nSELECT DISTINCT ON (u.id)\n    u.name, u.email,\n    COUNT(o.id) OVER (PARTITION BY u.id) as order_count\nFROM users u\nLEFT JOIN orders o ON o.user_id = u.id;\n```\n\n**Use CTEs for Clarity:**\n\n```sql\n-- Using Common Table Expressions\nWITH recent_users AS (\n    SELECT id, name, email\n    FROM users\n    WHERE created_at > NOW() - INTERVAL '30 days'\n),\nuser_order_counts AS (\n    SELECT user_id, COUNT(*) as order_count\n    FROM orders\n    WHERE created_at > NOW() - INTERVAL '30 days'\n    GROUP BY user_id\n)\nSELECT ru.name, ru.email, COALESCE(uoc.order_count, 0) as orders\nFROM recent_users ru\nLEFT JOIN user_order_counts uoc ON ru.id = uoc.user_id;\n```\n\n### Pattern 5: Batch Operations\n\n**Batch INSERT:**\n\n```sql\n-- Bad: Multiple individual inserts\nINSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');\nINSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com');\nINSERT INTO users (name, email) VALUES ('Carol', 'carol@example.com');\n\n-- Good: Batch insert\nINSERT INTO users (name, email) VALUES\n    ('Alice', 'alice@example.com'),\n    ('Bob', 'bob@example.com'),\n    ('Carol', 'carol@example.com');\n\n-- Better: Use COPY for bulk inserts (PostgreSQL)\nCOPY users (name, email) FROM '\u002Ftmp\u002Fusers.csv' CSV HEADER;\n```\n\n**Batch UPDATE:**\n\n```sql\n-- Bad: Update in loop\nUPDATE users SET status = 'active' WHERE id = 1;\nUPDATE users SET status = 'active' WHERE id = 2;\n-- ... repeat for many IDs\n\n-- Good: Single UPDATE with IN clause\nUPDATE users\nSET status = 'active'\nWHERE id IN (1, 2, 3, 4, 5, ...);\n\n-- Better: Use temporary table for large batches\nCREATE TEMP TABLE temp_user_updates (id INT, new_status VARCHAR);\nINSERT INTO temp_user_updates VALUES (1, 'active'), (2, 'active'), ...;\n\nUPDATE users u\nSET status = t.new_status\nFROM temp_user_updates t\nWHERE u.id = t.id;\n```\n\n## Advanced Techniques\n\n### Materialized Views\n\nPre-compute expensive queries.\n\n```sql\n-- Create materialized view\nCREATE MATERIALIZED VIEW user_order_summary AS\nSELECT\n    u.id,\n    u.name,\n    COUNT(o.id) as total_orders,\n    SUM(o.total) as total_spent,\n    MAX(o.created_at) as last_order_date\nFROM users u\nLEFT JOIN orders o ON u.id = o.user_id\nGROUP BY u.id, u.name;\n\n-- Add index to materialized view\nCREATE INDEX idx_user_summary_spent ON user_order_summary(total_spent DESC);\n\n-- Refresh materialized view\nREFRESH MATERIALIZED VIEW user_order_summary;\n\n-- Concurrent refresh (PostgreSQL)\nREFRESH MATERIALIZED VIEW CONCURRENTLY user_order_summary;\n\n-- Query materialized view (very fast)\nSELECT * FROM user_order_summary\nWHERE total_spent > 1000\nORDER BY total_spent DESC;\n```\n\n### Partitioning\n\nSplit large tables for better performance.\n\n```sql\n-- Range partitioning by date (PostgreSQL)\nCREATE TABLE orders (\n    id SERIAL,\n    user_id INT,\n    total DECIMAL,\n    created_at TIMESTAMP\n) PARTITION BY RANGE (created_at);\n\n-- Create partitions\nCREATE TABLE orders_2024_q1 PARTITION OF orders\n    FOR VALUES FROM ('2024-01-01') TO ('2024-04-01');\n\nCREATE TABLE orders_2024_q2 PARTITION OF orders\n    FOR VALUES FROM ('2024-04-01') TO ('2024-07-01');\n\n-- Queries automatically use appropriate partition\nSELECT * FROM orders\nWHERE created_at BETWEEN '2024-02-01' AND '2024-02-28';\n-- Only scans orders_2024_q1 partition\n```\n\n### Query Hints and Optimization\n\n```sql\n-- Force index usage (MySQL)\nSELECT * FROM users\nUSE INDEX (idx_users_email)\nWHERE email = 'user@example.com';\n\n-- Parallel query (PostgreSQL)\nSET max_parallel_workers_per_gather = 4;\nSELECT * FROM large_table WHERE condition;\n\n-- Join hints (PostgreSQL)\nSET enable_nestloop = OFF;  -- Force hash or merge join\n```\n\n## Best Practices\n\n1. **Index Selectively**: Too many indexes slow down writes\n2. **Monitor Query Performance**: Use slow query logs\n3. **Keep Statistics Updated**: Run ANALYZE regularly\n4. **Use Appropriate Data Types**: Smaller types = better performance\n5. **Normalize Thoughtfully**: Balance normalization vs performance\n6. **Cache Frequently Accessed Data**: Use application-level caching\n7. **Connection Pooling**: Reuse database connections\n8. **Regular Maintenance**: VACUUM, ANALYZE, rebuild indexes\n\n```sql\n-- Update statistics\nANALYZE users;\nANALYZE VERBOSE orders;\n\n-- Vacuum (PostgreSQL)\nVACUUM ANALYZE users;\nVACUUM FULL users;  -- Reclaim space (locks table)\n\n-- Reindex\nREINDEX INDEX idx_users_email;\nREINDEX TABLE users;\n```\n\n## Common Pitfalls\n\n- **Over-Indexing**: Each index slows down INSERT\u002FUPDATE\u002FDELETE\n- **Unused Indexes**: Waste space and slow writes\n- **Missing Indexes**: Slow queries, full table scans\n- **Implicit Type Conversion**: Prevents index usage\n- **OR Conditions**: Can't use indexes efficiently\n- **LIKE with Leading Wildcard**: `LIKE '%abc'` can't use index\n- **Function in WHERE**: Prevents index usage unless functional index exists\n\n## Monitoring Queries\n\n```sql\n-- Find slow queries (PostgreSQL)\nSELECT query, calls, total_time, mean_time\nFROM pg_stat_statements\nORDER BY mean_time DESC\nLIMIT 10;\n\n-- Find missing indexes (PostgreSQL)\nSELECT\n    schemaname,\n    tablename,\n    seq_scan,\n    seq_tup_read,\n    idx_scan,\n    seq_tup_read \u002F seq_scan AS avg_seq_tup_read\nFROM pg_stat_user_tables\nWHERE seq_scan > 0\nORDER BY seq_tup_read DESC\nLIMIT 10;\n\n-- Find unused indexes (PostgreSQL)\nSELECT\n    schemaname,\n    tablename,\n    indexname,\n    idx_scan,\n    idx_tup_read,\n    idx_tup_fetch\nFROM pg_stat_user_indexes\nWHERE idx_scan = 0\nORDER BY pg_relation_size(indexrelid) DESC;\n```\n",{"name":5,"description":7,"disable-model-invocation":57},true,"main","224d7699a283a75bd3f75d4d8b03b15aca0ae309","plugins\u002F10x-swe\u002Fskills\u002Fsql-optimization-patterns",0,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe","https:\u002F\u002Fgithub.com\u002Fcercova-studios","2026-11-12 07:39:44",{"source":8,"skillName":5,"commands":66,"prompt":76,"zipAvailable":57},[67,70,73],{"tool":68,"command":69},"npx","npx skills add cercova-studios\u002F10x-swe --skill sql-optimization-patterns",{"tool":71,"command":72},"bunx","bunx skills add cercova-studios\u002F10x-swe --skill sql-optimization-patterns",{"tool":74,"command":75},"pnpm","pnpm dlx skills add cercova-studios\u002F10x-swe --skill sql-optimization-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fsql-optimization-patterns\u002FSKILL.md",[78],{"path":79,"resourceType":80,"resourceTypeDesc":81,"sizeBytes":82,"sourceHtmlUrl":83},"agents\u002Fopenai.yaml","REFERENCE","参考文档",43,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fsql-optimization-patterns\u002Fagents\u002Fopenai.yaml",[85,121,156,176,195,207],{"skillNo":86,"name":87,"nameZh":6,"description":88,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":89,"licenseFileUrl":90,"sourceHtmlUrl":91,"categories":92,"keywords":94,"publishedAt":52},"01M6CD3T6EQ9N5KPNXCM6ABHVA","turnstile-spin","Set up Cloudflare Turnstile end-to-end in a project. Scan the codebase, create the widget via the Cloudflare API, embed it where user requests need bot verification (form submissions, SPA actions, API endpoints, download links, comment or vote submissions, etc.), wire canonical server-side siteverify in the customer's existing backend, validate, and persist the skill. Load this when a user asks to add Turnstile, set up CAPTCHA, protect a form or endpoint from bots, or fix a Turnstile integration. Uses Cloudflare's documented Turnstile contract.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fturnstile-spin\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fturnstile-spin\u002FSKILL.md",[93],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},[95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,39],"turnstile spin","SET","nextjs","actions","up","fix","cloudflare","bot","api","permissions","create","astro","server","verification","plugin","endpoints","customer","backend","sveltekit","integration","app","bots","spa","project","end","SWE",{"skillNo":122,"name":123,"nameZh":6,"description":124,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":89,"licenseFileUrl":125,"sourceHtmlUrl":126,"categories":127,"keywords":137,"publishedAt":52},"01M6CD0BJYRNV610HYYPX933RE","frontend-design","Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Ffrontend-design\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Ffrontend-design\u002FSKILL.md",[128,131,134],{"categoryNo":129,"categoryName":130,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":132,"categoryName":133,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":135,"categoryName":136,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000032","设计师",[138,139,140,105,141,142,143,144,145,146,48,147,148,149,150,151,152,39,153,154,155],"frontend design","frontend","design","web","quality","applications","creative","web components","Production","code","components","user","generic","aesthetics","pages","with","high","build",{"skillNo":157,"name":158,"nameZh":6,"description":159,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":160,"categories":161,"keywords":162,"publishedAt":52},"01M6CD4QX8C4DST98AY21HEYCM","source-insights","Prepare inspected source evidence, preserve exact citations, and publish reviewed insights into an explicit local library.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fsource-insights\u002FSKILL.md",[],[163,164,165,166,167,168,169,170,171,172,173,174,175],"source insights","insights","source","publish","Citations","evidence","library","workflows","prepare","session","global","local","preserve",{"skillNo":177,"name":178,"nameZh":6,"description":179,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":180,"categories":181,"keywords":185,"publishedAt":52},"01M6CD4N1HVNC1EXPEBZT7YS31","skill-graph","Discover skills and workflows through independent lexical search, relationship paths and a terminal graph.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fskill-graph\u002FSKILL.md",[182],{"categoryNo":183,"categoryName":184,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[186,187,109,170,188,189,190,173,191,192,193,120,194],"graph","skill graph","terminal","10x","search","discover skills","discover","paths","relationship",{"skillNo":196,"name":197,"nameZh":6,"description":198,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":199,"categories":200,"keywords":201,"publishedAt":52},"01M6CD4HQKXNZ57YEGD8QVK6Z6","session-search","Recall public session turns with exact provenance, bounded excerpts and independent piped exports.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fsession-search\u002FSKILL.md",[],[190,172,202,203,170,204,205,173,153,164,165,206],"session search","public","provenance","recall","bounded",{"skillNo":208,"name":209,"nameZh":6,"description":210,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":211,"categories":212,"keywords":219,"publishedAt":52},"01M6CD4ET7DVNBYPDAMAYMSK2T","newsletter","Produce a private local AI newsletter from bounded public research, with cited deep dives, HTML\u002FMarkdown output, Dagu scheduling and seven-day retention.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fnewsletter\u002FSKILL.md",[213,216],{"categoryNo":214,"categoryName":215,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000005","邮件与沟通",{"categoryNo":217,"categoryName":218,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000021","资料检索与研究",[209,220,221,222,223,203,170,224,225,226,227,173,153,228,229,174,206,230],"local ai","dagu","produce","research","markdown","scheduling","html","daily","deep","retention","output"]