Performance and scaling
This page is for database administrators who size the database of an Exponential site or look for the reason it is slow. It answers: how much of the traffic reaches the database at all, what does, and which levers help each engine. Sources: Database support, performance and scaling, What carries the read load and 10.12 Performance tuning.
Contents
- Most requests never reach the database
- What does reach it
- Connections and workers
- Per engine
- The levers, in order
- Checklist
Most requests never reach the database
| Layer | Setting | What a hit costs |
|---|---|---|
| Velocity response cache | settings/velocity.ini [CacheSettings] Enabled=enabled, DefaultTtl=30 | answered by Velocity's parent process: no PHP worker, no database; anonymous visitors only |
| Content view cache | site.ini [ContentSettings] ViewCaching=enabled | the main area of a page from a file |
| Template-block cache | site.ini [TemplateSettings] TemplateCache=enabled | menus and footers from files |
| SQL query cache | querycache.ini Mode=off by default | a repeated SELECT from APCu or a file; not on MongoDB (The SQL query cache) |
| Operating system file cache | database pages from memory after the first read |
The static cache ([ContentSettings] StaticCache) is disabled in the shipped installer and should stay off: with it on,
every publish regenerated the affected pages over HTTP inside the editor's request.
What does reach it
- the first views after a cache clear or a publish;
- signed-in editors and the administration;
- search (the built-in engine reads
ezsearch_*); - publishing, workflows, cronjobs, imports.
Size the database for these, not for the total page views. After a deploy that clears caches, expect a short burst
(the warm-up); exp:preload warms a site's pages on purpose (Preloading caches).
Connections and workers
- Under PHP-FPM each worker opens its own connection when a request needs one.
UsePersistentConnection=enabledkeeps it for the life of the worker (MySQL, PostgreSQL, Oracle). - Under Velocity with persistent workers (
settings/velocity.ini [ServerSettings] ForkPerRequest=disabled, the shipped value) each worker keeps the application, its connection and its caches warm. The pool size is[ServerSettings] Workers(shipped4), optionally dynamic withSpareWorkersandIdleWorkerTimeout(Velocity workers and pools). - Count the connections: PHP-FPM workers plus Velocity workers plus cron and console processes, per site, against the
server's limit (
max_connectionson MySQL and PostgreSQL, sessions or a DRCP pool on Oracle).
Per engine
| Engine | Levers |
|---|---|
| SQLite | reads scale with the number of processes; writes queue. Count up to 64 MB of page cache per process that opened the database (SQLitePragmas[]=cache_size=-16384 lowers it to 16 MB). ANALYZE after imports (SQLite maintenance) |
| PostgreSQL | row-level locking; persistent connections; your usual shared_buffers and autovacuum tuning; replication is external |
| MariaDB, MySQL | InnoDB row locking; persistent connections; innodb_buffer_pool_size sized for the working set; read replicas with UseSlaveServer (Read replicas) |
| MongoDB | performance follows the number of statements per page; create the indexes from bin/mongodb/create_indexes.js, without which subtree queries and URL alias lookups scan whole collections |
| Oracle | a new dedicated session costs tens of milliseconds: Persistent=enabled and DRCP; the Prefetch settings; statistics with gather-stats (Oracle tuning) |
Server parameters such as buffer pools are your engine's own; Exponential does not set or require particular values.
The levers, in order
- Caches on: view cache, template-block cache, Velocity's response cache; check them in Setup > System information, card Caches.
- Statistics current:
ANALYZE(SQLite, PostgreSQL),gather-stats(Oracle); MongoDB indexes created. - Find the statements: Finding slow queries; fix repeated queries at their source.
- Query cache
request, thenshared. - Persistent connections or Velocity's persistent workers.
- Replicas for MySQL and MariaDB; a bigger server or another engine when writes queue (Choosing an engine).
Measure each step with exp:benchmark --save and --baseline (Benchmark).
Checklist
- To do: Caches enabled; static cache off.
- To do: Connection count of all workers below the server's limit.
- To do: SQLite memory sized for
cache_sizeper worker. - To do: Statistics and indexes current.
- To do: Every change measured before and after.
Related pages
- Caching layers, PHP-FPM tuning
- Sizing memory, CPU and disk
- Monitoring the database
- Free documentation: this page is free to copy, translate and improve under the GNU FDL 1.3.
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.