我的问题是服务器只有4 GB内存
我必须做这样的更新查询:previous asked question
我的是这个:
set @orderid = 0;
update images im
set im.orderid = (select @orderid := @orderid + 1)
ORDER BY im.hotel_id, im.idImageType;
在im.hotel_id, im.idImageType
我有一个升序索引
在im.orderid
我也有一个升序索引。
该表有 21百万条记录,是一张MyIsam表。
表格如下:
CREATE TABLE `images` (
`photo_id` int(11) NOT NULL,
`idImageType` int(11) NOT NULL,
`hotel_id` int(11) NOT NULL,
`room_id` int(11) DEFAULT NULL,
`url_original` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
`url_max300` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
`url_square60` varchar(150) COLLATE utf8_unicode_ci NOT NULL,
`archive` int(11) NOT NULL DEFAULT '0',
`orderid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`photo_id`),
KEY `idImageType` (`idImageType`),
KEY `hotel_id` (`hotel_id`),
KEY `hotel_id_idImageType` (`hotel_id`,`idImageType`),
KEY `archive` (`archive`),
KEY `room_id` (`room_id`),
KEY `orderid` (`orderid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
问题在于性能:挂几分钟!
服务器磁盘也很忙。
我的问题是:有更好的方法可以达到同样的效果吗? 我是否要对桌子或其他东西进行分区以提高性能? 我无法修改服务器硬件,但可以调整MySql应用程序数据库服务器设置。
最好的问候
答案 0 :(得分:0)
您可以使用其中一些:
将引擎更新为InnoDB,它只会阻止一行,而不是更新所有表。
使用photo_id和良好的orderid创建#temp表,然后从这个temp更新你的表:
update images im, temp tp
set im.orderid = tp.orderid
where im.photo_id = tp.photo_id
这将是最快的方式,当您填写tmp表时 - 主表上没有块。
答案 1 :(得分:0)
KEY `hotel_id` (`hotel_id`),
KEY `hotel_id_idImageType` (`hotel_id`,`idImageType`),
DROP前者;后者照顾它的任何需要。 (这不会加快原始查询。)
“问题在于性能:挂几分钟!”有什么问题?
执行更新时,这个索引代价很高:
KEY `orderid` (`orderid`)
DROP并重新创建它。 (不要费心去掉其余部分。)与InnoDB一起使用的另一个原因是这些操作可以在不复制表的情况下完成(在5.6中)。 (21M行==很长时间,如果它必须复制表!)
除了photo_id之外,为什么要构建第二个唯一索引(orderid),它已经是唯一的?我问这个是因为可能有另一种方法来解决真正的问题,这个问题不涉及这个耗时的更新。
我还有两个更具体的建议,但我想先找到你的答案。
修改分页,按hotel_id, idImageType, photo_id
排序:
可以通过该三元组按顺序读取记录。甚至通过它们“分页”。
如果你在($hid, $type, $pid)
之后“离开”,这将是“下一个”20条记录:
WHERE hotel_id >= $hid
AND ( hotel_id > $hid
OR idImageType >= $type
AND ( idImageType > $type
OR photo_id > $pid
)
)
ORDER BY hotel_id, idImageType, photo_id
LIMIT 20
并且
INDEX(hotel_id, idImageType, photo_id)
这避免了orderid
及其耗时更新的需要。
一次分页hotel_id
会更简单。那会有用吗?
编辑2 - 消除停机时间
由于您要定期重新加载整个表,请在重新加载时执行此操作:
CREATE TABLE New
建议的索引更改。New
。 (一定要避免你的51分钟超时;我不知道是什么造成的。)RENAME TABLE images TO old, New TO images;
DROP TABLE old;
这样可以避免阻塞表加载和架构更改。原子步骤#3会有一个非常短的块。
每次重新加载数据时,请计划执行此过程。
另一个好处 - 在第2步之后,您可以测试新数据以查看它是否正常。
答案 2 :(得分:0)
这个问题涉及两个关键问题:
要在大型表上继续使用高效的paginate,我已经找到了一个解决方案,通过在表上进行先前的更新,但这样做会在更新所需的51分钟时间内出现问题,从而导致我的java基础架构超时(spring-批量步骤)。
现在在你的帮助下,我找到了两个大表上分页的解决方案,以及一个更新大表的解决方案。
要达到此性能,服务器需要内存。我使用 32 GB 内存在开发服务器上尝试此解决方案。
要像我需要的那样按照字段tupla进行分页,我创建了一个索引:
KEY `hotel_id_idImageType` (`hotel_id`,`idImageType`)
要实现新的解决方案,我们必须通过将主键部分添加到索引尾KEY hotel_id_idImageType (hotel_id,idImageType, primary key fields)
来更改此索引:
drop index hotel_id_idImageType on images;
create index hotelTypePhoto on images (hotel_id, idImageType, photo_id);
这是为了避免触摸表并仅使用索引文件......
假设我们想要19000000记录之后的10条记录。
此答案中的小数点为,
此解决方案非常实用,不需要额外字段orderid
,您不必在分页前进行任何更新:
select * from images im inner join
(select photo_id from images
order by hotel_id, idImageType, photo_id
limit 19000000,10) k
on im.photo_id = k.photo_id;
要使我的 2100万个表记录 上的表k只需要1.5秒,因为它只使用索引hotelTypePhoto
中的三个字段所以避免& #39; t访问表文件并仅在索引文件上工作。
订单就像原来的要求(hotel_id,idImageType),因为它包含在(hotel_id,idImageType,photo_id)中:相同的子集......
连接需要花时间,所以每次第一次在同一页面上执行分页时只需要1.5秒,如果你必须在3个月内批量执行它,这是个好时机。
在使用 4 GB内存 的生产服务器上,相同的查询需要3.5秒。
对表格进行分区无助于提高性能。
如果服务器将其置于缓存中,则时间会下降,或者如果您执行jdbc params语句,时间也会下降(我想)。
如果您经常使用它,它的优势在于它不关心数据是否发生变化。
此解决方案需要额外的字段orderid
,并且需要通过批量导入进行一次订单更新,并且在下次批量导入之前数据不得更改。
然后你可以在0,000秒内在桌面上分页。
set @orderid = 0;
update images im inner join (
select photo_id, (@orderid := @orderid + 1) as newOrder
from images order by hotel_id, idImageType, photo_id
) k
on im.photo_id = k.photo_id
set im.orderid = k.newOrder;
表k快速几乎与第一个解决方案相似。
这个全部更新只需要150,551秒比51分钟好得多! (150s vs 3060s)
在批处理中进行此更新后,您可以通过以下方式执行分页:
select * from images im where orderid between 19000000 and 19000010;
或更好
select * from images im where orderid >= 19000000 and orderid< 19000010;
这需要0,000秒来执行第一次和所有其他时间。
此解决方案是为了避免额外的字段和偏移使用。但需要记住最后一页的内容,如this solution
这是一个快速的解决方案,可以仅使用4GB内存在线服务器生产
假设您需要在20000000之后阅读最后十条记录 有两种情况需要注意:
在第二种情况下,您必须执行预查询才能找到起始页:
select hotel_id, idImageType, photo_id
from images im
order by hotel_id, idImageType, photo_id limit 20000000,1
它给了我:
+----------+-------------+----------+
| hotel_id | idImageType | photo_id |
+----------+-------------+----------+
| 1309878 | 4 | 43259857 |
+----------+-------------+----------+
这需要6,73秒
因此,您可以将此值存储在变量中以供下次使用
假设我们将@hot=1309878, @type=4, @photo=43259857
命名为
然后你可以在第二个查询中使用它:
select * from images im
where
hotel_id>@hot OR (
hotel_id=@hot and idImageType>@type OR (
idImageType=@type and photo_id>@photo
)
)
order by hotel_id, idImageType, photo_id limit 10;
第一个子句hotel_id>@hot
获取滚动索引上实际第一个字段后的所有记录但丢失了一些记录。为了实现它,我们必须执行OR子句,该子句将第一个索引字段全部保留为未读记录。
现在仅需0.1秒 但是这个查询可以被优化(bool distributive):
select * from images im
where
hotel_id>@hot OR (
hotel_id=@hot and
(idImageType>@type or idImageType=@type)
and (idImageType>@type or photo_id>@photo
)
)
order by hotel_id, idImageType, photo_id limit 10;
成为:
select * from images im
where
hotel_id>@hot OR (
hotel_id=@hot and
idImageType>=@type
and (idImageType>@type or photo_id>@photo
)
)
order by hotel_id, idImageType, photo_id limit 10;
成为:
select * from images im
where
(hotel_id>@hot OR hotel_id=@hot) and
(hotel_id>@hot OR
(idImageType>=@type and (idImageType>@type or photo_id>@photo))
)
order by hotel_id, idImageType, photo_id limit 10;
成为:
select * from images im
where
hotel_id>=@hot and
(hotel_id>@hot OR
(idImageType>=@type and (idImageType>@type or photo_id>@photo))
)
order by hotel_id, idImageType, photo_id limit 10;
它们是否与我们可以获得的限制数据相同?
要快速 不详尽 测试,请执行以下操作:
select im.* from images im inner join (
select photo_id from images order by hotel_id, idImageType, photo_id limit 20000000,10
) k
on im.photo_id=k.photo_id
order by im.hotel_id, im.idImageType, im.photo_id;
这需要6,56秒,数据与上面的查询相同 所以测试是积极的。
在这个解决方案中,你只需要第一次在第一页上阅读就可以花费6,73秒(但如果你需要所有你想要的话)。
要实现所有其他页面,您只需要0,10秒即可获得非常好的结果。
感谢rick对他基于商店最后一页阅读的解决方案的暗示。
在 解决方案1 上,您没有任何额外字段,每页需要3.5秒 在 解决方案2 上,您有额外的字段,需要一个大内存服务器(32 GB测试),在150秒内。但是你会在0,000秒内阅读该页面 在 解决方案3 上,您没有任何额外字段,但必须存储最后一页读取指针,如果您没有从第一页开始阅读,则必须花费6 ,第一页73秒。然后你在所有其他页面上只花了0.10秒。
祝你好运
解决方案3 正是Rick所建议的。对不起,我之前的 解决方案3 我犯了一个错误,当我编写正确的解决方案时,我已经应用了一些布尔规则,如分配属性等等,之后我得到了相同的Rich解决方案! 问候