원클릭으로
performance-guide
Performance optimization for PHP, JavaScript, databases, and caching strategies
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Performance optimization for PHP, JavaScript, databases, and caching strategies
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
RESTful API design patterns, HTTP standards, versioning, error handling, and documentation
Joomla 4/5 component development with MVC, services, plugins, and language handling
Joomla 3.x legacy patterns with JFactory, non-namespaced MVC, JDatabase, and plugin structure
Laravel best practices for Eloquent, controllers, validation, services, and testing
PHP coding standards including strict typing, OOP patterns, error handling, and documentation
Deep dive into SOLID principles with PHP/TypeScript examples, refactoring patterns, and violation detection
| name | performance-guide |
| description | Performance optimization for PHP, JavaScript, databases, and caching strategies |
| license | MIT |
| compatibility | opencode |
| metadata | {"type":"optimization","languages":"php, javascript, sql"} |
Problem:
$users = User::all();
foreach ($users as $user) {
echo $user->profile->bio; // Query per user!
}
// 1 query for users + N queries for profiles = N+1
Solution - Eager Loading:
// Laravel
$users = User::with('profile')->get();
// Doctrine
$qb->select('u', 'p')
->from(User::class, 'u')
->leftJoin('u.profile', 'p');
// Joomla
$query->select($db->quoteName(['u.*', 'p.bio']))
->from($db->quoteName('#__users', 'u'))
->leftJoin($db->quoteName('#__profiles', 'p') . ' ON p.user_id = u.id');
// Bad
$users = User::all(); // SELECT *
// Good
$users = User::select(['id', 'name', 'email'])->get();
-- Index columns used in:
-- WHERE clauses
CREATE INDEX idx_users_status ON users(status);
-- JOIN conditions
CREATE INDEX idx_orders_user_id ON orders(user_id);
-- ORDER BY
CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
-- Composite for common queries
CREATE INDEX idx_orders_user_status ON orders(user_id, status);
-- MySQL
EXPLAIN SELECT * FROM users WHERE status = 'active';
-- Look for:
-- type: ALL (bad) vs index/ref (good)
-- rows: Lower is better
-- Extra: "Using filesort" or "Using temporary" = potential issue
// Bad - loads all into memory
User::all()->each(fn($user) => process($user));
// Good - processes in chunks
User::chunk(1000, function ($users) {
foreach ($users as $user) {
process($user);
}
});
// Laravel lazy collection
User::lazy()->each(fn($user) => process($user));
// Bad
foreach ($items as $item) {
$count = count($items); // Recalculated each iteration
// ...
}
// Good
$count = count($items);
foreach ($items as $item) {
// Use $count
}
// For checking existence - O(1) vs O(n)
// Bad
$allowed = ['admin', 'moderator', 'user'];
if (in_array($role, $allowed)) { }
// Good
$allowed = ['admin' => true, 'moderator' => true, 'user' => true];
if (isset($allowed[$role])) { }
// Bad for many concatenations
$html = '';
foreach ($items as $item) {
$html .= '<li>' . $item . '</li>';
}
// Better
$parts = [];
foreach ($items as $item) {
$parts[] = '<li>' . $item . '</li>';
}
$html = implode('', $parts);
// Best - use output buffering or templates
// Bad - loads all into memory
function getUsers(): array
{
return User::all()->toArray();
}
// Good - yields one at a time
function getUsers(): Generator
{
foreach (User::cursor() as $user) {
yield $user;
}
}
<template>
<!-- Use v-once for static content -->
<header v-once>{{ staticTitle }}</header>
<!-- Use v-memo for expensive re-renders -->
<div v-memo="[item.id, item.selected]">
<ExpensiveComponent :item="item" />
</div>
<!-- Always key v-for -->
<div v-for="item in items" :key="item.id">
{{ item.name }}
</div>
</template>
// Components
const HeavyComponent = defineAsyncComponent(() =>
import('./HeavyComponent.vue')
)
// Routes
const routes = [
{
path: '/dashboard',
component: () => import('./views/Dashboard.vue')
}
]
import { useDebounceFn, useThrottleFn } from '@vueuse/core'
// Debounce - wait until user stops typing
const search = useDebounceFn((query: string) => {
fetchResults(query)
}, 300)
// Throttle - max once per interval
const scroll = useThrottleFn(() => {
updateScrollPosition()
}, 100)
// worker.ts
self.onmessage = (e) => {
const result = heavyComputation(e.data)
self.postMessage(result)
}
// main.ts
const worker = new Worker('./worker.ts')
worker.postMessage(data)
worker.onmessage = (e) => {
result.value = e.data
}
Request → Application Cache → Database Cache → Database
(Redis/Memcached) (Query Cache)
// Simple cache
$users = Cache::remember('users:active', 3600, function () {
return User::where('status', 'active')->get();
});
// Tagged cache (for invalidation)
Cache::tags(['users'])->put("user:{$id}", $user, 3600);
Cache::tags(['users'])->flush(); // Clear all user cache
// Cache with lock (prevent stampede)
$users = Cache::lock('users:lock')->block(5, function () {
return Cache::remember('users:all', 3600, fn() => User::all());
});
return response($content)
->header('Cache-Control', 'public, max-age=3600')
->header('ETag', md5($content));
| Tool | Use Case |
|---|---|
| Xdebug | PHP step debugging & profiling |
| Blackfire | PHP performance profiling |
| Laravel Telescope | Request/query debugging |
| Symfony Profiler | Built-in profiling toolbar |
| Chrome DevTools | JS performance & network |
| Vue DevTools | Component render performance |
EXPLAIN ANALYZE | SQL query analysis |