具有 150000+ 行的表响应速度太慢

问题描述 投票:0回答:2

我面临着奇怪的缓慢,有时它会说#1205 - 超过锁定等待超时;尝试在我的特定 MySQL 表中重新启动事务

我有下表,其中包含 idTBO_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_hotels
选择计数(TBO_code),其中 city_code =115936
) 作为总计数
从 TBO_hotels 出发
其中城市代码 = 115936
按 id ASC 排序
限制 0.50;

我不明白我做错了什么,因为一切似乎都是正确的。

mysql
2个回答
1
投票

有东西锁住了

乍一看,问题是因为

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)

找到锁

也许有一个查询锁定了表,例如大的插入或更新。由于此查询必须扫描整个表,因此任何行上的独占锁都可能会阻塞整个查询。检查您的慢速查询日志检查锁


0
投票

尝试以下查询来查看 LOCK 表,然后解锁它

SHOW OPEN TABLES 
WHERE `Table` LIKE '%wp_%' 
  AND `Database` LIKE '[DB NAME]' 
  AND In_use > 0;
© www.soinside.com 2019 - 2024. All rights reserved.