Drupal网站利用数据库来保存配置和内容。
在普遍情况下(小规模部署),这个数据库是很紧凑的。例如我管理的这个网站一般只在5-20M之间。数据库尺寸主要收到内容数量和模块的影响。
然而,我曾经被一条主机商发来的通知吓了一跳,说我的网站使用了超过2G的存储,我想一定是出了什么问题。
这里我会分享我解决这个问题的一些心得,我想如果你遇到这些问题,也会有相似的情况。
(提示一下,可以使用drush sqlc来在你的网站数据库上运行SQL命令)
数据库层面
找到受影响的数据库。一般来说,每个网站对应一个数据库——除非你在使用一个多站点配置。
SELECT
table_schema "DB Name",
ROUND(SUM(data_length + index_length) / 1024 / 1024, 1) "DB Size in MB"
FROM information_schema.tables
GROUP BY table_schema;
+--------------------+---------------+
| DB Name | DB Size in MB |
+--------------------+---------------+
| information_schema | 0.2 |
| drupal_database | 1110.2 |
+--------------------+---------------+
2 rows in set (0.01 sec)
这里你会发现,我的数据库用户只能看到两个数据库,information_schema十一个内部数据库,主数据库叫做drupal_database
数据表层面
下一步是来查明让数据库膨胀至此的原因。对数据库中的表进行排查。
我发现“order by size”很有用,他只会显示五个最大的表,着很可能就是问题所在。如果不是这样,那可能是个好消息——你的网站已经成长到了如此规模。
SELECT
table_name,
table_rows,
data_length,
index_length,
ROUND(((data_length + index_length) / 1024 / 1024),2) 'Table Size in MB'
FROM information_schema.tables
WHERE table_type = 'BASE TABLE'
ORDER BY data_length DESC
LIMIT 5;
+---------------------+------------+-------------+--------------+------------------+
| table_name | table_rows | data_length | index_length | Table Size in MB |
+---------------------+------------+-------------+--------------+------------------+
| queue | 137362 | 1137704424 | 4017152 | 1088.83 |
| field_revision_body | 1731 | 5259276 | 154624 | 5.16 |
| field_data_body | 1731 | 5259276 | 145408 | 5.15 |
| feeds_log | 27455 | 2712868 | 1131520 | 3.67 |
| menu_router | 401 | 406128 | 76800 | 0.46 |
+---------------------+------------+-------------+--------------+------------------+
5 rows in set (0.01 sec)
在我的例子中,queue表占用了98%的空间,这就是问题了。
Drupal使用queue表来存储将被cron运行的任务,如果cron成功运行,那么这里应该是个空表,或者在上次cron运行之后产生的很少几条记录。
任务层面
为了查明事实,我查看了一下这个表中的task类型。
SELECT
name,
COUNT(1)
FROM queue
GROUP BY name;
+---------------------+----------+
| name | COUNT(1) |
+---------------------+----------+
| feeds_source_import | 137498 |
+---------------------+----------+
1 row in set (0.07 sec)
这里只剩下一条结果,是feeds模块用于从rss导入内容创建的任务。检查了一下这个导入设置,我发现,这个任务被配置为15分钟一次,然而cron被配置为每小时运行一次。这意味着,每次cron运行,是无法完成所有的任务的,所以任务数据就会持续增长下去了。
解决问题也很简单,提高cron的运行频率,降低导入触发频率,来确保cron能够顺利完成所有任务。
这里对膨胀的表的处理还有一点遗留问题,如果cron能够顺利完成,数据表应该恢复正常大小。如果你不放心,可以直接truncate这张表,当然是在你知道这一行为的后果是否会影响必要任务的情况下。
基准测试
下面是同一个查询在一个”正常”的网站下的运行结果。
这里你会看到,没有什么数据在尺寸上鹤立鸡群,这个数据库只有10M。
+--------------------+---------------+
| DB Name | DB Size in MB |
+--------------------+---------------+
| information_schema | 0.2 |
| drupal_database | 6.1 |
+--------------------+---------------+
2 rows in set (0.12 sec)
+---------------------+------------+-------------+--------------+------------+
| TABLE_NAME | table_rows | data_length | index_length | Size in MB |
+---------------------+------------+-------------+--------------+------------+
| field_revision_body | 423 | 1556716 | 47104 | 1.53 |
| menu_router | 450 | 425076 | 80896 | 0.48 |
| system | 390 | 313544 | 73728 | 0.37 |
| field_data_body | 37 | 135968 | 18432 | 0.15 |
| registry | 965 | 94016 | 53248 | 0.14 |
+---------------------+------------+-------------+--------------+------------+
5 rows in set (0.02 sec)
+----------+
| count(1) |
+----------+
| 0 |
+----------+
1 row in set (0.00 sec)