我的表
Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
userid int(11) NO MUL NULL
title varchar(50) YES NULL
hosting varchar(10) YES NULL
zipcode varchar(5) YES NULL
lat varchar(20) YES NULL
long varchar(20) YES NULL
msg varchar(1000)YES MUL NULL
time datetime NO NULL
那就是桌子。我已经模拟了500k行数据并随机删除了270k行,只留下了230k,自动增量为500k。
以下是我的索引
Keyname Type Unique Packed Field Cardinality Collation Null
PRIMARY BTREE Yes No id 232377 A
info BTREE No No userid 2003 A
lat 25819 A YES
long 25819 A YES
title 25819 A YES
time 25819 A
考虑到这一点,这是我的问题:
SELECT * FROM
posts
WHERElong
> -118.13902802886 ANDlong
< -118.08130797114 ANDlat
> 33.79987197114 ANDlat
< 33.85759202886订购BY id ASC LIMIT 0,25
显示0到15行(总共16行,查询耗时1.5655秒)[id:32846 - 540342]
该查询只给我带来了1页,但由于它必须搜索所有230k记录,所以它仍需要1.5秒。
以下是查询说明:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE posts index NULL PRIMARY 4 NULL 25 Using where
所以,即使我使用where子句只能获得16个结果,我仍然会得到一个缓慢的查询。
现在举例来说,如果我进行更广泛的搜索:
SELECT * FROM `posts` WHERE `long`>-118.2544681443 AND `long`<-117.9658678557 AND `lat`>33.6844318557 AND `lat`<33.9730321443 ORDER BY id ASC LIMIT 0, 25
显示0到24行(总共25行,查询耗时0.0849秒)[id:691 - 29818]
从20页中检索第一页时发现速度要快得多,483发现总数,但我限制在25页。
但如果我要求最后一页
SELECT * FROM `posts` WHERE `long`>-118.2544681443 AND `long`<-117.9658678557 AND `lat`>33.6844318557 AND `lat`<33.9730321443 ORDER BY id ASC LIMIT 475, 25
显示0到7行(总计8行,查询耗时1.5874秒)[id:553198 - 559593]
我的查询速度很慢。
我的问题是如何实现良好的分页?当网站上线时,我预计当它起飞时,每天都会删除数百个帖子。 帖子应按ID或时间戳排序,而Id不是连续的,因为某些记录将被删除。 我希望有一个标准的分页
1 2 3 4 5 6 7 8 ... [Last Page]
答案 0 :(得分:2)
使用WHERE
子句从先前页面上显示的结果记录中进行过滤:然后您不需要指定偏移量,只需要指定行数。例如,跟踪上次看到的id或时间戳,并仅筛选id或时间戳大于该值的记录。
答案 1 :(得分:0)
答案 2 :(得分:0)
几句话。
鉴于你order by id
,这意味着在每个页面上你有第一个和最后一个记录的id,所以你应该使用id&gt; $ last_id限制20,这将是非常快。
缺点显然是你不能提供“最后”页面或介于两者之间的任何页面,如果id不是顺序的(在两者之间删除)。然后,您可以使用最后已知的id和偏移+限制组合的组合。
显然,拥有适当的索引也有助于排序和限制。
答案 3 :(得分:0)
看起来你只有一个主键索引。您可能希望在所使用的字段上定义索引,例如:
create index idx_posts_id on posts (`id` ASC);
create index idx_posts_id_timestamp on posts (`id` ASC, `timestamp` ASC);
除了你的主要唯一密钥索引之外,在你的密钥字段上有一个常规索引,通常有助于加速mysql,A LOT。
答案 4 :(得分:0)
Mysql在大偏移量下失去了相当多的性能:来自mysqlPerformance blog:
小心大限制使用索引进行排序是有效的,如果您需要前几行,即使进行了一些额外的过滤,因此您需要按LIMIT请求按索引扫描更多行。但是,如果您处理LIMIT查询具有较大的偏移效率将受到影响。 LIMIT 1000,10可能比LIMIT 0,10慢。确实,大多数用户在结果中不会超过10页,但搜索引擎机器人可能会这样做。我见过机器人在我的项目中看了200多页。此外,对于许多未能处理此问题的网站,提供了一个非常容易的任务来启动DOS攻击 - 从少数连接请求包含大量数字的页面就足够了。如果您不做任何其他事情,请确保阻止页码太大的请求。
对于某些情况,例如,如果结果是静态的,那么预先计算结果可能是有意义的,这样您就可以查询它们的位置。 因此,不是使用LIMIT 1000,10查询,而是在1000和1009之间的WHERE位置,对于任何位置都具有相同的效率(只要它被索引)
答案 5 :(得分:0)
如果您使用的是AUTO INCREMENT,您可以使用:
SELECT *
FROM
{帖子{1}} ID为
WHERE
ID为>= 200000 ORDER BY
这样mysql只能遍历200000以上的行。
答案 6 :(得分:0)
我明白了。让我失望的是订单。因为我会打电话给一个限制而且我要求越走越远,它就越需要排序。那么我通过添加子查询来修复它,首先使用WERE
子句提取我想要的数据,然后使用ORDER BY
和LIMIT
SELECT * FROM
(SELECT * from `posts` as `p`
WHERE
`p`.`long`>-119.2544681443
AND `p`.`long`<-117.9658678557
AND `p`.`lat`>32.6844318557 A
ND `p`.`lat`<34.9730321443
) as posttable
order by id desc
limit x,n
通过这样做,我实现了以下目标:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3031 Using filesort
2 DERIVED p ALL NULL NULL NULL NULL 232377 Using where
现在我使用“where”过滤232k结果,仅使用orderby并限制3031结果。
显示行0 - 3030(总共3,031行,查询占用0.1431秒)