Chamilo is a tracking-heavy learning management system. Every time a learner opens a course, answers a quiz question, posts in a forum, or simply clicks through a lesson, the platform writes rows into logging and access tables. On a quiet installation this is invisible, but a busy course catalog with hundreds of active users can push the track_* family of tables into millions of rows within a single academic term. When those tables outgrow their indexes and the server's buffer pool, page loads slow down, the gradebook stalls, and reports time out. On shared hosting you cannot tune the MySQL/MariaDB engine itself, so maintenance has to happen at the schema and data level through phpMyAdmin.

This article walks through identifying which Chamilo tables are bloated, repairing corruption, pruning expired data safely, and confirming that the indexes Chamilo ships with are actually intact. Everything here runs inside cPanel Jupiter or DirectAdmin Evolution with an unprivileged hosting account.

Locating the right database and finding the bloat

Chamilo keeps its database credentials in app/config/configuration.php inside your document root. Open cPanel's File Manager (or DirectAdmin's File Manager), browse to that file, and look for the connection block. You will see entries similar to this:

$_configuration['db_host'] = 'localhost';
$_configuration['db_user'] = 'myuser_chamilo';
$_configuration['db_password'] = '********';
$_configuration['main_database'] = 'myuser_chamilo';

Note the main_database value. Open phpMyAdmin from the cPanel or DirectAdmin dashboard and select that database in the left sidebar. Before touching anything, go to the Structure tab for the whole database. phpMyAdmin lists every table with its row count and a Size column. Click the Size header to sort descending. On almost every aging Chamilo install, the largest tables will be from the tracking subsystem:

  • track_e_access and track_e_access_complete — one row per page access
  • track_e_lastaccess — tool-level access logging
  • track_e_default — general event tracking
  • track_e_online — who-is-online data that should stay tiny but sometimes doesn't purge
  • track_e_item_property and track_e_exercises — exercise attempt detail
  • c_lp_item_view — learning path step views

To get a precise picture rather than relying on the rounded Structure values, run this query from the SQL tab. Replace the schema name with your own main_database:

SELECT table_name,
       table_rows,
       ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_mb,
       ROUND(data_length / 1024 / 1024, 2) AS data_mb,
       ROUND(index_length / 1024 / 1024, 2) AS index_mb
FROM information_schema.tables
WHERE table_schema = 'myuser_chamilo'
ORDER BY (data_length + index_length) DESC
LIMIT 25;

Pay attention to the ratio between data_mb and index_mb. If a table has far more index than data, or if data_length stays high after you delete rows, you are looking at fragmentation and free space that was never reclaimed. The row counts here are estimates for InnoDB tables, but they are accurate enough to tell a 2,000-row table from a 4-million-row one.

Repairing broken tables and overhead

Connection errors and sudden "Database error" messages in Chamilo frequently trace back to a crashed or marked-as-corrupt table rather than a credential problem. This is more common on legacy MyISAM tables, though InnoDB can also report errors after an ungraceful server restart or a disk-quota event that interrupted a write.

In phpMyAdmin, open the database Structure view and tick the checkboxes beside the suspect tables (or use Check all). From the With selected dropdown at the bottom, choose Check table. phpMyAdmin runs CHECK TABLE and reports the status. Any table returning something other than OK needs attention. For MyISAM tables you can then select Repair table from the same dropdown, which issues REPAIR TABLE directly.

InnoDB does not support REPAIR TABLE, and you cannot use the server-level innodb_force_recovery option without root. The supported recovery path for an InnoDB table on shared hosting is to rebuild it, which forces the engine to rewrite the data file and often clears soft corruption and fragmentation at the same time:

OPTIMIZE TABLE track_e_access;

For InnoDB, MySQL translates OPTIMIZE TABLE into a table rebuild plus analyze, and you may see a note saying exactly that — it is harmless. You can also trigger the same rebuild through the Operations tab of a single table using the Optimize table link. Run these one table at a time on large tables to avoid hitting your account's CPU or query-time limits. If a specific table consistently throws errors during these operations, export it with the Export tab as a safety copy before doing anything else, and open a support ticket so the engineering team can inspect the engine logs you cannot reach.

Pruning tracking data and reclaiming space

The safest and most effective win is removing tracking rows you will never report on again. Chamilo exposes some of this through the admin interface: log in as a platform administrator and visit Administration → System / Platform maintenance, where older Chamilo builds offer a tool to clean up the "who is online" and statistics data. If your version lacks a complete purge there, you can prune in phpMyAdmin with date-bounded deletes.

Always back up first. Use phpMyAdmin's Export tab, pick Custom, select only the tracking tables, and save a compressed SQL file to your machine. Then delete in bounded batches rather than one enormous statement, which keeps each query under your hosting query-time limit and avoids locking:

DELETE FROM track_e_access
WHERE access_date < '2024-01-01'
LIMIT 50000;

Re-run the same statement until phpMyAdmin reports zero rows affected, then move to the next table. The equivalent date columns differ per table: track_e_default uses default_date, track_e_lastaccess uses access_date, and track_e_online uses login_date. Confirm the column name in the Structure tab before running a delete. Because InnoDB does not shrink the data file after deletes, follow a large purge with OPTIMIZE TABLE on that table to return the freed space to the operating system and refresh the index statistics.

Resist the urge to truncate c_lp_item_view, track_e_exercises, or track_e_attempt wholesale. Those tables feed the gradebook and certificate logic — deleting active-course rows will erase learner progress. Scope every delete to terms or courses that are genuinely archived.

Checking indexes and preventing recurrence

Slow gradebook and report pages usually mean a query is scanning a table instead of using an index. You can confirm this without server access. Take a query from a slow page — the attempt lookup is a common offender — and prefix it with EXPLAIN in the phpMyAdmin SQL tab:

EXPLAIN SELECT * FROM track_e_exercises
WHERE exe_user_id = 42 AND exe_cours_id = 'ENG101';

If the type column reads ALL and rows is large, no index is being used. Compare the table's current indexes against a clean Chamilo install by opening the Structure tab and scrolling to the Indexes section. The tracking tables ship with indexes on user and course columns; if a previous migration or a failed import dropped them, you can restore the standard one, for example:

ALTER TABLE track_e_exercises
  ADD INDEX idx_user_course (exe_user_id, exe_cours_id);

Only add indexes that mirror what the stock schema defines or what your EXPLAIN output clearly justifies — extra indexes slow down the heavy insert traffic these tables already carry.

To keep bloat from returning, lower how much Chamilo logs. Under Administration → Configuration settings → Platform, review the course and session tracking options and disable detailed page-by-page access logging if you do not run per-click reports. Schedule a quarterly review of the information_schema size query above, and if PHP timeouts interrupt long maintenance queries, raise max_execution_time for the session by adding a line to a .user.ini file in your document root:

max_execution_time = 120

That change applies to PHP page execution and admin tools, not to phpMyAdmin's own SQL runner, which is governed by the hosting panel. For persistent engine-level errors, mismatched storage engines, or tables you cannot rebuild, raise a ticket — those are the cases where root-level inspection is the correct next step.