标签 索引 下的文章

数据库索引损坏引起的问题排查

这个问题排查耗费了我很多时间,主要原因在于开始没找到问题根源,找错了排查方向。

问题描述:
网站后台查看版块列表显示有版块A,前台版块列表也显示有版块A,但是点击版块A链接提示版块不存在或已被删除。这里假设此版块ID为61。

排查过程:
根据表象猜测可能是缓存了数据,印证这点需要到数据库里确认是否没有版块A的数据了。
于是进Mysql,执行下面的命令:

select * from cdb_forums where fid = 61 or fup = 61;

得到结果显示没有数据,自己感觉前面的猜测得到了验证,于是确定按缓存的原因进行排查。

首先第一个想到的缓存是memcache,因为前面查过一个问题知道官方开启了memcache缓存机制。
在db_mysql.class.php文件里记录memcache查询的结果,显示查询出的数据确实有fid=61和fup=61的结果。
嗯,看来前面的推测确实没问题,是memcache缓存了sql数据。

中间这里捣鼓了半天memcache的命令,因为有部分memcache的代码被注释了,在这里耗费了较多时间,第一天的排查没找到原因。

第二天继续。
写测试脚本,代码类似如下:

$memcache = new Memcache;
$memcache->connect($memhost, $memport) or die('Memcached cannot connected');
$key = '***'; // memcahce缓存的KEY
// 获取memcahce数据
$res = $memcache->get($key);
echo 'result:
'; print_r($res); // ======== echo '

'; // 更新memcahce数据 $memcache->set($key, '', '0', 1800); // test为测试更新的数据 // 获取memcahce数据 $res1 = $memcache->get($key); echo 'result:
'; print_r($res1);

执行后发现后面的输出为空,即表示清除memcahce缓存后,memcahce里没数据了。
现在回到前台刷新,发现仍然显示版块A。
到这里,排除memcahce缓存的可能,那还可能是什么缓存的呢?
这时候想到模板,但是仔细想了下,Discuz的模板缓存不会缓存数据的,对了,还有文件缓存cache_***.php。
进入cache目录下清理掉缓存文件,重新刷新,前台仍然显示。

呃,好像前面的推断有问题,照排查的结果来看不属于缓存的问题。
好吧,继续找其他的原因。
前面记录memcahce缓存内容的时候,我同时记录的执行的sql。
我找到查询版块的sql,然后进入Mysql,执行sql,输出让我大吃一惊。
居然查询到了fup=61的记录,输出里明晃晃的显示了几条fup=61的记录。
我擦,这是什么情况啊!我记得很清楚,昨天我用WHERE fid = 61 or fup =61查询的时候没有数据。
执行下面的命令:

select * from cdb_forums where fup =61;

输出显示没有数据。
执行下面的命令:

select * from cdb_forums where fup like '61';

输出居然有结果。

焦虑,这是神马情况。
一开始想到是不是61里还有其他空白字符,但是看了下表结果这个字段的类型是smallint,这是不可能的。

后来突然想到索引的问题,查了下该表的索引,发现fup是索引。
执行下面的命令:

select * from cdb_forums ignore index(fup) where fup = '61';

不使用fup索引进行查询,输出有数据。

好吧,现在可以确定应该是索引的问题。
执行下面的修复命令:

repair table cdb_forums QUICK;

修复成功,再次执行查询的命令:

select * from cdb_forums where fup = 61;

输出有数据。

这个时候前台再次刷新,终于不显示版块A了。
泪奔了,耗了快一天的问题搞定了,就是小小的索引问题。

这次排查的总结:
前面下推断的时间太早,事后想想当时推测是memcache缓存的时候有过一个过期时间的疑问,但没深究,没搞透彻memcache的机制就判断属于memcache的原因。排查问题一定要找到根源,问题再深,一层一层的捋,总能找到原因。