저는 많은 다른 고객들이 사용하는 SaaS (Software-as-a-Service) 응용 프로그램의 수석 개발자입니다. 우리의 소프트웨어는 MySQL 백엔드로 구동되는 Apache / PHP 애플리케이션 서버 클러스터에서 실행됩니다. 에 하나 개의 소프트웨어의 특정 인스턴스, 카테고리 이름의 목록을 조회 할 PHP 코드가 시간 초과되어 고객이 29 개 이상의 범주가있을 때 . 나는 이것이 의미가 없다는 것을 안다. 숫자 30에 대해서는 특별한 점이 없으며 다른 고객이 30 개가 넘는 범주를 가지고 있지만,이 하나의 설치에 30 개 이상의 범주가 있으면 문제가 100 % 재현되고 30 개 미만의 범주가 있으면 사라집니다.
해당 테이블은 다음과 같습니다.
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(64) NOT NULL,
`title` varchar(128) NOT NULL,
`parent` int(10) unsigned NOT NULL,
`keywords` varchar(255) NOT NULL,
`description` text NOT NULL,
`status` enum('Active','Inactive','_Deleted','_New') NOT NULL default 'Active',
`style` enum('_Unknown') default NULL COMMENT 'Autoenum;',
`order` smallint(5) unsigned NOT NULL,
`created_at` datetime NOT NULL,
`modified_at` datetime default NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`),
KEY `parent` (`parent`),
KEY `created_at` (`created_at`),
KEY `modified_at` (`modified_at`),
KEY `status` (`status`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 COMMENT='R2' AUTO_INCREMENT=33 ;
문제의 코드는 반복적으로 테이블을 쿼리하여 모든 범주를 가져옵니다. 그것은 발행
SELECT * FROM `categories` WHERE `parent`=0 ORDER BY `order`,`name`
그런 다음 반환 된 각 행마 다이 쿼리를 반복하지만 WHERE parent=$category_id매번 사용 합니다. (이 절차가 개선 될 수 있다고 확신하지만 다른 질문 일 수 있습니다)
내가 알 수있는 한 다음 쿼리는 영원히 걸려 있습니다.
SELECT * FROM `categories` WHERE `parent`=22 ORDER BY `order`,`name`
서버의 mysql 클라이언트 에서이 쿼리를 완벽하게 실행할 수 있으며 PHPMyAdmin에서도 문제없이 실행할 수 있습니다.
그렇지 않은 것을 참고 특정 쿼리 문제입니다. 내가 만약 DELETE FROM categories WHERE id=22다음 다른 후 중단됩니다 위의 것과 유사한 쿼리. 또한 위의 쿼리 는 수동으로 실행할 때 0 행을 반환합니다 .
나는 테이블이 손상되었다고 의심했지만 REPAIR TABLE, OPTIMIZE TABLE보고 된 이러한 문제점들에 대해서는 문제를 해결하지도 않았다. 테이블을 삭제하고 다시 만들었지 만 문제가 다시 발생했습니다. 이것은 정확히 동일한 테이블 구조이며 다른 고객이 사용하는 PHP 코드는 30 개 이상의 범주를 가진 고객을 포함하여 다른 사람에게는 아무런 문제가 없습니다.
PHP 코드는 영원히 되풀이 되지 않습니다 . (이것은 무한 루프 가 아닙니다 )
MySQL 서버는 i686 (MySQL Community Edition (GPL))에서 pc-linux-gnu 용 mysqld Ver 5.0.92-community와 함께 CentOS Linux를 실행 중입니다.
MySQL 서버의로드가 낮음 :로드 평균 : 0.58, 0.75, 0.73, CPU : 4.6 % us, 2.9 % sy, 0.0 % ni, 92.2 % id, 0.0 % wa, 0.0 % hi, 0.3 % si, 0.0 % st. 무시할만한 스왑 사용 중 (448k)
이 문제를 어떻게 해결할 수 있습니까? 무슨 일이 일어나고 있는지에 대한 제안?
UPDATE : I는 TRUNCE표 에드과 더미 데이터 (30)의 행을 삽입 :
INSERT INTO `categories` (`id`, `name`, `title`, `parent`, `keywords`, `description`, `status`, `style`, `order`, `created_at`, `modified_at`) VALUES
(1, 'New Category', '', 0, '', '', 'Inactive', NULL, 1, '2011-10-25 12:06:30', '2011-10-25 12:06:34'),
(2, 'New Category', '', 0, '', '', 'Inactive', NULL, 2, '2011-10-25 12:06:39', '2011-10-25 12:06:40'),
(3, 'New Category', '', 0, '', '', 'Inactive', NULL, 3, '2011-10-25 12:06:41', '2011-10-25 12:06:42'),
(4, 'New Category', '', 0, '', '', 'Inactive', NULL, 4, '2011-10-25 12:06:46', '2011-10-25 12:06:47'),
(5, 'New Category', '', 0, '', '', 'Inactive', NULL, 5, '2011-10-25 12:06:49', NULL),
(6, 'New Category', '', 0, '', '', 'Inactive', NULL, 6, '2011-10-25 12:06:51', '2011-10-25 12:06:52'),
(7, 'New Category', '', 0, '', '', 'Inactive', NULL, 7, '2011-10-25 12:06:53', '2011-10-25 12:06:54'),
(8, 'New Category', '', 0, '', '', 'Inactive', NULL, 8, '2011-10-25 12:06:56', '2011-10-25 12:06:57'),
(9, 'New Category', '', 0, '', '', 'Inactive', NULL, 9, '2011-10-25 12:06:59', '2011-10-25 12:06:59'),
(10, 'New Category', '', 0, '', '', 'Inactive', NULL, 10, '2011-10-25 12:07:01', '2011-10-25 12:07:01'),
(11, 'New Category', '', 0, '', '', 'Inactive', NULL, 11, '2011-10-25 12:07:03', '2011-10-25 12:07:03'),
(12, 'New Category', '', 0, '', '', 'Inactive', NULL, 12, '2011-10-25 12:07:05', '2011-10-25 12:07:05'),
(13, 'New Category', '', 0, '', '', 'Inactive', NULL, 13, '2011-10-25 12:07:06', '2011-10-25 12:07:07'),
(14, 'New Category', '', 0, '', '', 'Inactive', NULL, 14, '2011-10-25 12:07:08', '2011-10-25 12:07:09'),
(15, 'New Category', '', 0, '', '', 'Inactive', NULL, 15, '2011-10-25 12:07:11', '2011-10-25 12:07:12'),
(16, 'New Category', '', 0, '', '', 'Inactive', NULL, 16, '2011-10-25 12:07:13', '2011-10-25 12:07:14'),
(17, 'New Category', '', 0, '', '', 'Inactive', NULL, 17, '2011-10-25 12:09:41', '2011-10-25 12:09:42'),
(18, 'New Category', '', 0, '', '', 'Inactive', NULL, 18, '2011-10-25 12:09:47', NULL),
(19, 'New Category', '', 0, '', '', 'Inactive', NULL, 19, '2011-10-25 12:09:48', NULL),
(20, 'New Category', '', 0, '', '', 'Inactive', NULL, 20, '2011-10-25 12:09:48', NULL),
(21, 'New Category', '', 0, '', '', 'Inactive', NULL, 21, '2011-10-25 12:09:49', NULL),
(22, 'New Category', '', 0, '', '', 'Inactive', NULL, 22, '2011-10-25 12:09:50', NULL),
(23, 'New Category', '', 0, '', '', 'Inactive', NULL, 23, '2011-10-25 12:09:51', NULL),
(24, 'New Category', '', 0, '', '', 'Inactive', NULL, 24, '2011-10-25 12:09:51', NULL),
(25, 'New Category', '', 0, '', '', 'Inactive', NULL, 25, '2011-10-25 12:09:52', NULL),
(26, 'New Category', '', 0, '', '', 'Inactive', NULL, 26, '2011-10-25 12:09:53', NULL),
(27, 'New Category', '', 0, '', '', 'Inactive', NULL, 27, '2011-10-25 12:09:54', NULL),
(28, 'New Category', '', 0, '', '', 'Inactive', NULL, 28, '2011-10-25 12:09:55', NULL),
(29, 'New Category', '', 0, '', '', 'Inactive', NULL, 29, '2011-10-25 12:09:56', NULL),
(30, 'New Category', '', 0, '', '', 'Inactive', NULL, 30, '2011-10-25 12:09:57', NULL);
부모가 전혀 없으며 모든 카테고리가 최상위에 있습니다. 문제는 여전히 있습니다. PHP에 의해 실행 된 다음 쿼리는 실패합니다.
SELECT * FROM `categories` WHERE `parent`=22 ORDER BY `order`,`name`
여기에 EXPLAIN:
mysql> EXPLAIN SELECT * FROM `categories` WHERE `parent`=22 ORDER BY `order`,`name`;
+----+-------------+------------+------+---------------+--------+---------+-------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+--------+---------+-------+------+-----------------------------+
| 1 | SIMPLE | categories | ref | parent | parent | 4 | const | 1 | Using where; Using filesort |
+----+-------------+------------+------+---------------+--------+---------+-------+------+-----------------------------+
1 row in set (0.00 sec)
업데이트 # 2 : 이제 다음을 모두 시도했습니다.
- 이 테이블과 데이터를 동일한 소프트웨어로 다른 사이트에 복사했습니다. 문제가 표를 따르지 않았습니다 . 이 하나의 데이터베이스에 국한된 것 같습니다.
- gbn의 답변이 제안한대로 색인을 변경했습니다. 문제는 남아 있었다.
- 테이블을 삭제하고 테이블로 다시
InnoDB만들고 위의 동일한 30 개의 테스트 행을 삽입했습니다. 문제는 남아 있었다.
이 데이터베이스와 관련이 있다고 생각합니다 ...
업데이트 # 3 : 데이터베이스를 완전히 삭제하고 새 이름으로 다시 작성하여 데이터를 가져 왔습니다. 문제는 남아있다.
나는 실제 PHP 문이에 대한 호출임을 발견했다 mysql_query(). 이 이후의 명령문은 실행되지 않습니다.
호출이 중단되는 동안 MySQL은 스레드를 휴면 상태로 표시합니다!
mysql> show full processlist;
+-------+------------------+-----------------------------+----------------------+---------+------+-------+-----------------------+
| Id | User | Host | db | Command | Time | State | Info |
+-------+------------------+-----------------------------+----------------------+---------+------+-------+-----------------------+
| 5560 | root | localhost | problem_db | Query | 0 | NULL | show full processlist |
----- many rows which have no relevancy; only rows from this customer's app are shown ------
| 16341 | shared_db | oak01.sitepalette.com:53237 | shared_db | Sleep | 308 | | NULL |
| 16342 | problem_db | oak01.sitepalette.com:60716 | problem_db | Sleep | 307 | | NULL |
| 16344 | shared_db | oak01.sitepalette.com:53241 | shared_db | Sleep | 308 | | NULL |
| 16346 | problem_db | oak01.sitepalette.com:60720 | problem_db | Sleep | 308 | | NULL |
+-------+------------------+-----------------------------+----------------------+---------+------+-------+-----------------------+
업데이트 # 4 : 위에서 설명한 테이블과 556 개의 행이 있는 두 테이블 의 조합으로 범위를 좁혔습니다 . 경우 테이블 미만 556 개 행을 포함, 또는 테이블 미만 30 개 행이 문제가 사라집니다. 그것은 내가 여기에 타격하고있는 일종의 MySQL 한계와 같습니다 ...categoriesmedia_imagesmedia_imagescategories
업데이트 # 5 : 방금 데이터베이스를 다른 MySQL 서버로 옮기려고했는데 문제가 사라졌습니다 ... 그래서 프로덕션 데이터베이스 서버와 관련이 있습니다 ...
업데이트 # 6 : 매번 멈추는 관련 PHP 코드는 다음과 같습니다.
public function find($type,$conditions='',$order='',$limit='')
{
if($this->_link == self::AUTO_LINK)
$this->_link = DFStdLib::database_connect();
if(is_resource($this->_link))
{
$q = "SELECT ".($type==_COUNT?'COUNT(*)':'*')." FROM `{$this->_table}`";
if($conditions)
{
$q .= " WHERE $conditions";
}
if($order)
{
$q .= " ORDER BY $order";
}
if($limit)
{
$q .= " LIMIT $limit";
}
switch($type)
{
case _ALL:
DFSkel::log(DFSkel::LOG_DEBUG,"mysql_query($q,$this->_link);");
$res = @mysql_query($q,$this->_link);
DFSkel::log(DFSkel::LOG_DEBUG,"res = $res");
이 코드는 프로덕션 환경 에 있으며 다른 모든 설치에서 잘 작동 합니다. 한 번의 설치로에 중단됩니다 $res = @mysql_query($q,$this->_link);. 난을 참조하기 때문에 알고 mysql_query디버그 로그에, 아니라 res =, 나는이시 strace는 PHP 공정, 그것은에 걸려 있어요read(
업데이트 # 무엇이든 -가 - 인 - I-증오 this- & (# ^ & -issue! 이 지금 일어나고 시작했다 둘 개 . 내 고객 난 그냥 해고 tcpdump그것은 모양 의 MySQL의 응답이 완전히 전송되지 않습니다. 전체 MySQL 응답을 보내기 전에 TCP 스트림이 중단 된 것 같습니다 (그러나 여전히 조사 중입니다)
업데이트 # 완전히 사라졌습니다.하지만 미친 듯이 작동합니다. 이제는 말이되지 않지만 해결책을 찾았습니다. MySQL 서버의 eth2인터페이스에 두 번째 IP 주소를 할당하고 NFS 트래픽에 하나의 IP를 사용하고 MySQL에 두 번째 IP를 사용하면 문제가 사라집니다. NFS + MySQL 트래픽이 모두 해당 IP로 이동하는 경우 어떻게 든 IP 주소를 오버로드하는 것과 같습니다. 그러나 IP 주소를 "오버로드"할 수 없기 때문에 이치에 맞지 않습니다. 인터페이스의 포화 상태는 확실하지만 동일한 인터페이스입니다.
도대체 무슨 일이 일어나고 있는지 아십니까? 이것은 아마도 unix.SE 또는 ServerFault 질문 일 것입니다 ... (적어도 지금은 작동합니다 ...)
업데이트 # why-oh-why : 이 문제는 여전히 발생합니다. 두 개의 다른 IP를 사용해도 시작되었습니다. 새 개인 IP를 계속 만들 수 있지만 분명히 문제가 있습니다.