2gb表有1000万行,后期分页选择很慢

时间:2016-03-24 03:50:35

标签: mysql sql query-optimization

我在MySQL中有一个包含1000万行和2 GB数据的表 选择IN LIFO格式数据很慢

表格引擎 = int permissionCheck = ContextCompat.checkSelfPermission(thisActivity, android.Manifest.permission.WRITE_CALENDAR);

表格中有一个主键和一个唯一键

InnoDB

我如何提高表的性能。 ?

表格结构

SELECT * FROM link LIMIT 999999 , 50;

注意: id int(11) NO PRI NULL auto_increment url varchar(255) NO UNI NULL website varchar(100) NO NULL state varchar(10) NO NULL type varchar(100) NO NULL prio varchar(100) YES NULL change varchar(100) YES NULL last varchar(100) YES NULL 正在SELECT * FROM link LIMIT 1 , 50;,但是当前的SQL正在花费.9ms 100次更多

5 个答案:

答案 0 :(得分:5)

这很可能是由于“早期行查找”

可以强制MySQL进行“后期行查找”。请尝试以下查询

SELECT  l.*
FROM    (
        SELECT  id
        FROM    link
        ORDER BY
                id
        LIMIT 999999 , 50
        ) q
JOIN    link l
ON      l.id = q.id

查看这篇文章

MySQL limit clause and rate low lookups

答案 1 :(得分:5)

对于下一步上一页按钮,您可以使用WHERE子句代替OFFSET

示例(使用LIMIT 10 - 下面说明的示例数据):您在某个页面上显示10行,其中包含ID [2522,2520,2514,2513,2509,2508,2506,2504,2497,2496]。在我的情况下,这是用

创建的
select *
from link l
order by l.id desc
limit 10
offset 999000

对于下一页,您将使用

limit 10
offset 999010

获取带有[2495,2494,2493,2492,2491,2487,2483,2481,2479,2475]的行。

对于上一页,您将使用

limit 10
offset 998990

获取带有[2542,2541,2540,2538,2535,2533,2530,2527,2525,2524]的行。

以上所有查询都在 500毫秒中执行。使用"技巧" Sanj建议它仍然需要 250毫秒

现在,使用minId=2496maxId=2522的给定页面,我们可以使用{{1}为 Next Last 按钮创建查询条款。

下一步按钮:

WHERE

结果ID:select * from link l where l.id < :minId -- =2496 order by l.id desc limit 10

上一页按钮:

[2495,2494,2493,2492,2491,2487,2483,2481,2479,2475]

结果ID:select * from link l where l.id > :maxId -- =2522 order by l.id asc limit 10

要颠倒顺序,您可以在子选择中使用查询:

[2524,2525,2527,2530,2533,2535,2538,2540,2541,2542]

结果ID:select * from ( select * from link l where l.id > 2522 order by l.id asc limit 10 ) sub order by id desc

这些查询在&#34; no time&#34;中执行。 (小于1毫秒)并提供相同的结果。

您无法使用此解决方案来创建页码。但我不认为你会输出200K的页码。

测试数据:

使用

创建了用于示例和基准的数据
[2542,2541,2540,2538,2535,2533,2530,2527,2525,2524]

其中CREATE TABLE `link` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `url` VARCHAR(255) NOT NULL, `website` VARCHAR(100) NULL DEFAULT NULL, `state` VARCHAR(10) NULL DEFAULT NULL, `type` VARCHAR(100) NULL DEFAULT NULL, `prio` VARCHAR(100) NULL DEFAULT NULL, `change` VARCHAR(100) NULL DEFAULT NULL, `last` VARCHAR(100) NULL DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE INDEX `url` (`url`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB; insert into link select i.id , concat(id, '-', rand()) url , rand() website , rand() state , rand() `type` , rand() prio , rand() `change` , rand() `last` from test._dummy_indexes_2p23 i where i.id <= 2000000 and rand() < 0.5 是一个包含2 ^ 23个ID(约8M)的表。因此,数据包含每隔一个id随机丢失的大约1M行。表大小:228 MB

答案 2 :(得分:0)

我已将SQL查询更新为此,这花费的时间更少。

 SELECT * FROM link ORDER BY id LIMIT 999999 , 50  ;

答案 3 :(得分:0)

由于数据量很大,

提高查询响应时间的提示很少:

  1. 将存储引擎Innodb更改为myisam。
  2. 创建表分区 (https://dev.mysql.com/doc/refman/5.7/en/partitioning-management.html
  3. Mysql群集(http://dev.mysql.com/doc/refman/5.7/en/mysql-cluster-overview.html
  4. 增加硬件容量。
  5. 由于

答案 4 :(得分:0)

首先在没有任何订单的情况下在您的桌面上运行不保证您的查询如果运行两次将返回相同的数据。 最好添加ORDER BY子句。将id作为一个好的候选人,因为它是您的主键并且看起来很独特(因为它是auto_increment值。)

您可以将此作为基础:

SELECT * FROM link ORDER BY id LIMIT 50;

这将为您提供表格中的前50行。

现在接下来的50行,我们可以保存查询中的最后一个位置,而不是使用OFFSET

您可以保存上一个查询中最后一行ID的ID,并在下一个查询中使用它:

SELECT * FROM link WHERE id > last_id ORDER BY id LIMIT 50;

这将为您提供最后一个ID之后的下50行。

查询在OFFSET的高值上运行缓慢的原因是因为mysql必须在给定OFFSET的所有行上运行并返回最后LIMIT行数。这意味着较大的OFFSET是查询运行得越慢。

我上面显示的解决方案不依赖于OFFSET,因此查询将以与当前页面无关的相同速度运行。

另请参阅此有用的文章,其中介绍了您可以选择的其他一些选项:http://www.iheavy.com/2013/06/19/3-ways-to-optimize-for-paging-in-mysql/