偶爾,隨機間隔,我們的網站完全癱瘓。MySQL查詢癱瘓網站
看着SHOW FULL PROCESSLIST;
,我注意到,當出現這種情況,有可能是「Copying to tmp table
」的過長...時間(有時350秒)特定的查詢,幾乎所有的查詢都是「Locked
」。
我不明白的部分是,90%的時間,這個查詢運行良好。我看到它在進程列表中出現,大部分時間都很快完成。 此查詢正在我們的主頁上通過ajax調用,根據您的瀏覽歷史記錄(亞馬遜)顯示產品推薦。
有時,隨機(但是太頻繁),它會卡在「複製到tmp表」中。
下面是該查詢的實例釣到這是增長109秒的時候,我看了看:
SELECT DISTINCT product_product.id, product_product.name, product_product.retailprice, product_product.imageurl, product_product.thumbnailurl, product_product.msrp
FROM product_product, product_xref, product_viewhistory
WHERE
(
(product_viewhistory.productId = product_xref.product_id_1 AND product_xref.product_id_2 = product_product.id)
OR
(product_viewhistory.productId = product_xref.product_id_2 AND product_xref.product_id_1 = product_product.id)
)
AND product_product.outofstock='N'
AND product_viewhistory.cookieId = '188af1efad392c2adf82'
AND product_viewhistory.productId IN (24976, 25873, 26067, 26073, 44949, 16209, 70528, 69784, 75171, 75172)
ORDER BY product_xref.hits DESC
LIMIT 10
當然的「Cookie編號」,並動態根據請求「的productId」修改名單。
我使用php與PDO。
編輯:我想通了一些涉及到的表結構可能會有所幫助:
CREATE TABLE IF NOT EXISTS `product_viewhistory` (
`userId` int(10) unsigned NOT NULL default '0',
`cookieId` varchar(30) collate utf8_unicode_ci NOT NULL,
`productId` int(11) NOT NULL,
`viewTime` timestamp NOT NULL default CURRENT_TIMESTAMP,
KEY `userId` (`userId`),
KEY `cookieId` (`cookieId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `product_xref` (
`id` int(11) NOT NULL auto_increment,
`product_id_1` int(11) default NULL,
`product_id_2` int(11) default NULL,
`hits` int(11) NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `IDX_PROD1` (`product_id_1`),
KEY `IDX_PROD2` (`product_id_2`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=184531 ;
CREATE TABLE IF NOT EXISTS `product_product` (
`id` int(11) NOT NULL auto_increment,
`supplierid` int(11) NOT NULL default '0',
`suppliersku` varchar(100) NOT NULL default '',
`name` varchar(100) NOT NULL default '',
`cost` decimal(10,2) NOT NULL default '0.00',
`retailprice` decimal(10,2) NOT NULL default '0.00',
`weight` decimal(10,2) NOT NULL default '0.00',
`imageurl` varchar(255) NOT NULL default '',
`thumbnailurl` varchar(255) NOT NULL default '',
`sizechartlink` varchar(255) NOT NULL default '',
`content` text NOT NULL,
`remark` varchar(100) NOT NULL default '',
`colorchartlink` varchar(255) default NULL,
`outofstock` char(1) NOT NULL default '',
`summary` text NOT NULL,
`freehandoutlink` varchar(255) default NULL,
`msrp` decimal(10,2) default NULL,
`enabled` tinyint(1) NOT NULL default '1',
`sales_score` float NOT NULL default '0',
`sales_score_offset` float NOT NULL default '0',
`date_added` timestamp NULL default CURRENT_TIMESTAMP,
`brand` varchar(255) default NULL,
`tag_status` varchar(20) default NULL,
PRIMARY KEY (`id`),
KEY `product_retailprice_idx` (`retailprice`),
KEY `suppliersku` (`suppliersku`),
FULLTEXT KEY `product_name_summary_ft` (`name`,`summary`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
另外,根據要求,結果的解釋道:
+----+-------------+---------------------+------+---------------------+----------+---------+-------+-------+------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+------+---------------------+----------+---------+-------+-------+------------------------------------------------+
| 1 | SIMPLE | product_xref | ALL | IDX_PROD1,IDX_PROD2 | NULL | NULL | NULL | 30035 | Using temporary; Using filesort |
| 1 | SIMPLE | product_viewhistory | ref | cookieId | cookieId | 92 | const | 682 | Using where |
| 1 | SIMPLE | product_product | ALL | PRIMARY | NULL | NULL | NULL | 31880 | Range checked for each record (index map: 0x1) |
+----+-------------+---------------------+------+---------------------+----------+---------+-------+-------+------------------------------------------------+
3 rows in set (0.00 sec)
當我意識到我做了
新的更新版本根本不需要product_viewhistory。我是從舊的代碼左起:
SELECT DISTINCT product_product.id, product_product.name, product_product.retailprice, product_product.imageurl, product_product.thumbnailurl, product_product.msrp
FROM product_product, product_xref
WHERE
(
(product_xref.product_id_1 IN (24976, 25873, 26067, 26073, 44949, 16209, 70528, 69784, 75171, 75172) AND product_xref.product_id_2 = product_product.id)
OR
(product_xref.product_id_2 IN (24976, 25873, 26067, 26073, 44949, 16209, 70528, 69784, 75171, 75172) AND product_xref.product_id_1 = product_product.id)
)
AND product_product.outofstock='N'
ORDER BY product_xref.hits DESC
LIMIT 10
而新的解釋:
+----+-------------+-----------------+-------------+---------------------+---------------------+---------+------+-------+-------------------------------------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------------+---------------------+---------------------+---------+------+-------+-------------------------------------------------------------------------------------+
| 1 | SIMPLE | product_xref | index_merge | IDX_PROD1,IDX_PROD2 | IDX_PROD1,IDX_PROD2 | 5,5 | NULL | 32 | Using sort_union(IDX_PROD1,IDX_PROD2); Using where; Using temporary; Using filesort |
| 1 | SIMPLE | product_product | ALL | PRIMARY | NULL | NULL | NULL | 31880 | Range checked for each record (index map: 0x1) |
+----+-------------+-----------------+-------------+---------------------+---------------------+---------+------+-------+-------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)
注意它是如何顯示「可能的鍵」,但在「鍵」中它說「NULL」。爲什麼?? – 2010-05-28 17:41:47
確實存在問題。 'product_xref'和'product_product'表在這個查詢中沒有使用索引,導致掃描超過30000行(每個!)'臨時使用;在EXPLAIN outout中使用filesort'通常是一個紅旗,如果可能的話應該檢查並修復它。 不幸的是,我不是這方面的大師,所以希望這裏的其他人能夠指出你正確的方向,只要你需要採取的實際步驟。您可能還想檢查谷歌。使用EXPLAIN優化MySQL查詢的信息很多。 – x1a4 2010-05-28 17:43:06
好吧,我認爲我剛剛查詢了很多,因爲我意識到我不需要product_viewhistory表。這是多餘的,從以前的版本留下的代碼... – 2010-05-28 18:07:13