我面临着奇怪的缓慢,有时它会说#1205 - 超过锁定等待超时;尝试在我的特定 MySQL 表中重新启动事务。
我有下表,其中包含 id 和 TBO_code 作为索引,如下所示的结构以及超过 150000 行数据
--
-- Table structure for table `TBO_hotels`
--
CREATE TABLE `TBO_hotels` (
`id` bigint(20) NOT NULL,
`TBO_code` varchar(50) DEFAULT NULL,
`name` varchar(255) NOT NULL,
`address` text NOT NULL,
`Map` varchar(255) NOT NULL,
`city_code` varchar(255) NOT NULL,
`country` varchar(255) NOT NULL,
`zip_code` varchar(50) NOT NULL,
`city_name` varchar(255) DEFAULT NULL,
`rating` varchar(255) DEFAULT NULL,
`HotelFacilities` text DEFAULT NULL,
`contact_phone` varchar(255) DEFAULT NULL,
`country_code` varchar(255) DEFAULT NULL,
`featured_image` varchar(255) DEFAULT NULL,
`images` text DEFAULT NULL,
`description` text DEFAULT NULL,
`Attractions` text DEFAULT NULL,
`CheckInTime` text NOT NULL,
`CheckOutTime` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
--
-- Indexes for dumped tables
--
--
-- Indexes for table `TBO_hotels`
--
ALTER TABLE `TBO_hotels`
ADD PRIMARY KEY (`id`),
ADD KEY `TBO_code` (`TBO_code`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `TBO_hotels`
--
ALTER TABLE `TBO_hotels`
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT;
COMMIT;
当我尝试搜索相对于列
city_code
* 的行时(其他城市代码主表中使用的列值)*,它的响应速度非常慢
即使我只是简单地浏览表格或尝试使用 phpMyAdmin, 进行排序
下面是一个示例查询,我搜索了全局变量,在全局设置中也没有发现任何奇怪的地方。
即使我已经有了正确的索引数据,但该特定表中的响应很慢。
选择*,
(从选择计数(TBO_code),其中 city_code =115936TBO_hotels
) 作为总计数
从 TBO_hotels 出发
其中城市代码 = 115936
按 id ASC 排序
限制 0.50;
我不明白我做错了什么,因为一切似乎都是正确的。
乍一看,问题是因为
city_code
上没有索引。虽然是的,这是一个问题,但它的表现不应该那么糟糕。 150,000 行并不算大。在我的笔记本电脑上,查询在不到 100 毫秒的时间内完成。
问题就在错误消息中:
#1205 - Lock wait timeout exceeded
。有东西长时间锁定表或表中的一行。
如果
city_code
没有索引,则必须搜索整个表。首先,它必须扫描整个表,找到所有匹配的行并对其进行计数(如下Table scan on test
)。然后它将扫描 id
索引 (Index scan on test using PRIMARY
),直到找到 50 行具有匹配的 city_code
(Filter: (test.city_code = 115936)
)。根据城市代码的分布方式,这可能是整个表。在我的测试数据中,有 450,000 行,它必须搜索 150050 行((actual time=0.0488..51.4 rows=150050 loops=1)
)
mysql> explain analyze SELECT *, (SELECT count(*) from test where city_code =115936 ) as TotalCount FROM test where city_code = 115936 ORDER BY id ASC LIMIT 0,50;
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Limit: 50 row(s) (cost=4.53 rows=5) (actual time=51.9..66.1 rows=50 loops=1)
-> Filter: (test.city_code = 115936) (cost=4.53 rows=5) (actual time=51.9..66.1 rows=50 loops=1)
-> Index scan on test using PRIMARY (cost=4.53 rows=50) (actual time=0.0488..51.4 rows=150050 loops=1)
-> Select #2 (subquery in projection; run only once)
-> Aggregate: count(0) (cost=49878 rows=1) (actual time=152..152 rows=1 loops=1)
-> Filter: (test.city_code = 115936) (cost=45369 rows=45088) (actual time=39..152 rows=1504 loops=1)
-> Table scan on test (cost=45369 rows=450883) (actual time=0.0597..111 rows=451504 loops=1)
|
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
如果我们添加索引,MySQL并不一定能很好地使用索引。这是在 city_code 和
optimize table test
上添加索引后的计划。它实际上做了同样的事情,但它现在扫描整个 city_code
索引。
mysql> explain analyze SELECT *, (SELECT count(*) from test where city_code =115936 ) as TotalCount FROM test where city_code = 115936 ORDER BY id ASC LIMIT 0,50;
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Limit: 50 row(s) (cost=4.65 rows=5) (actual time=58.1..71.7 rows=50 loops=1)
-> Filter: (test.city_code = 115936) (cost=4.65 rows=5) (actual time=58.1..71.7 rows=50 loops=1)
-> Index scan on test using PRIMARY (cost=4.65 rows=50) (actual time=0.0393..57.1 rows=150050 loops=1)
-> Select #2 (subquery in projection; run only once)
-> Aggregate: count(0) (cost=51052 rows=1) (actual time=149..149 rows=1 loops=1)
-> Filter: (test.city_code = 115936) (cost=46530 rows=45216) (actual time=17.3..148 rows=1504 loops=1)
-> Covering index scan on test using test_city_code_idx (cost=46530 rows=452155) (actual time=0.0345..106 rows=451504 loops=1)
|
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set, 4 warnings (0.22 sec)
也许有一个查询锁定了表,例如大的插入或更新。由于此查询必须扫描整个表,因此任何行上的独占锁都可能会阻塞整个查询。检查您的慢速查询日志并检查锁。
尝试以下查询来查看 LOCK 表,然后解锁它
SHOW OPEN TABLES
WHERE `Table` LIKE '%wp_%'
AND `Database` LIKE '[DB NAME]'
AND In_use > 0;