ฉันเป็นผู้พัฒนาอาวุโสในแอปพลิเคชัน Software-as-a-Service ที่ลูกค้าหลายรายใช้กัน ซอฟต์แวร์ของเราทำงานบนคลัสเตอร์ของแอพพลิเคชันเซิร์ฟเวอร์ Apache / PHP ขับเคลื่อนโดยแบ็กเอนด์ MySQL เมื่อวันหนึ่งอินสแตนซ์ของซอฟต์แวร์โค้ด PHP ในการค้นหารายชื่อประเภทที่จะหมดเวลาเมื่อลูกค้ามีมากกว่า 29 ประเภท ฉันรู้ว่ามันไม่สมเหตุสมผล ไม่มีอะไรพิเศษเกี่ยวกับหมายเลข 30 ที่จะทำลายสิ่งนี้และลูกค้ารายอื่น ๆ ที่มีมากกว่า 30 หมวดหมู่อย่างไรก็ตามปัญหาคือทำซ้ำได้ 100% เมื่อการติดตั้งครั้งนี้มี 30 หมวดหมู่หรือมากกว่าและหายไปเมื่อมีน้อยกว่า 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
แล้วแตกต่างกันแบบสอบถามคล้ายกับที่ดังกล่าวข้างต้นแล้วจะแขวน นอกจากนี้แบบสอบถามดังกล่าวข้างต้นผลตอบแทนที่ศูนย์แถวเมื่อผมทำงานด้วยตนเอง
ฉันสงสัยว่าตารางอาจเสียหายและฉันพยายามREPAIR TABLE
และOPTIMIZE TABLE
แต่ปัญหาเหล่านี้ไม่ได้รับการรายงานและไม่สามารถแก้ไขปัญหาได้ ฉันทิ้งโต๊ะและสร้างใหม่ แต่ปัญหากลับมา นี่คือโครงสร้างตารางเดียวกันและรหัส PHP ที่ลูกค้ารายอื่นใช้โดยไม่มีปัญหาสำหรับคนอื่นรวมถึงลูกค้าที่มีมากกว่า 30 หมวดหมู่
รหัส PHP จะไม่เรียกซ้ำตลอดไป (นี่ไม่ใช่และลูปไม่สิ้นสุด)
เซิร์ฟเวอร์ MySQL กำลังใช้งาน CentOS linux พร้อม mysqld Ver 5.0.92-community สำหรับ pc-linux-gnu บน i686 (MySQL Community Edition (GPL))
โหลดบนเซิร์ฟเวอร์ MySQL ต่ำ: โหลดเฉลี่ย: 0.58, 0.75, 0.73, Cpu (s): 4.6% เรา, 2.9% sy, 0.0% ni, 92.2% id, 0.0% wa, 0.0% hi, 0.3% si, 0.0% ST มีการใช้การแลกเปลี่ยนเล็กน้อย (448k)
ฉันจะแก้ไขปัญหานี้ได้อย่างไร ข้อเสนอแนะใด ๆ เกี่ยวกับสิ่งที่อาจเกิดขึ้น?
UPDATE:ฉัน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 |
+-------+------------------+-----------------------------+----------------------+---------+------+-------+-----------------------+
UPDATE # 4:ฉันได้ จำกัด ให้แคบลงเป็นการรวมกันของสองตารางcategories
ตารางรายละเอียดด้านบนและmedia_images
ตารางที่มี 556 แถว หากmedia_images
ตารางมีน้อยกว่า 556 แถวหรือcategories
ตารางมีน้อยกว่า 30 แถวปัญหาจะหายไป มันเหมือนเป็นข้อ จำกัด MySQL บางอย่างที่ฉันไปถึงที่นี่ ...
อัปเดต # 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(
อัปเดต # ไม่ว่ามันจะเป็นอะไรฉันเกลียดสิ่งนี้ & (# ^ & - ออกใหม่!ตอนนี้เริ่มเกิดขึ้นกับลูกค้าของฉันสองคนฉันเพิ่งเริ่มทำงานtcpdump
และดูเหมือนว่าการตอบสนองจาก MySQL จะไม่ถูกส่งอย่างสมบูรณ์ ดูเหมือนว่ากระแส TCP จะหยุดทำงานก่อนที่จะส่งการตอบสนอง MySQL แบบเต็ม (ฉันยังคงตรวจสอบอยู่)
อัปเดต # ฉันได้ไปอย่างบ้าคลั่ง แต่มันทำงานได้แล้วตอนนี้เลย:โอเคมันไม่สมเหตุสมผล แต่ฉันได้พบวิธีแก้ปัญหาแล้ว ถ้าฉันกำหนดที่อยู่ IP ที่สองให้กับeth2
อินเทอร์เฟซของเซิร์ฟเวอร์ MySQL และใช้หนึ่ง IP สำหรับการรับส่งข้อมูล NFS และ IP ที่สองสำหรับ MySQL ปัญหาจะหายไป มันก็เหมือนฉัน ... กำลังโหลดที่อยู่ IP มากเกินไปถ้าทั้ง NFS + MySQL ทราฟฟิกทั้งคู่ไปที่ไอพีนั้น แต่นั่นทำให้รู้สึกเป็นศูนย์เพราะคุณไม่สามารถ "เกิน" ที่อยู่ IP ขัดจังหวะอินเทอร์เฟซแน่นอน แต่เป็นอินเทอร์เฟซเดียวกัน
มีความคิดอะไรเกิดขึ้นที่นี่ นี่อาจเป็นคำถาม unix.SE หรือ ServerFault ณ จุดนี้ ... (อย่างน้อยก็ใช้ได้ในตอนนี้ ... )
อัปเดต # Why-oh-ทำไม:ปัญหานี้ยังคงเกิดขึ้น มันเริ่มเกิดขึ้นแม้ใช้ IP ที่ต่างกันสองตัว ฉันสามารถสร้าง IP ส่วนตัวใหม่ ๆ ได้ แต่ก็มีบางอย่างผิดปกติ