首页 > 其他分享 >limit语句的优化

limit语句的优化

时间:2022-11-03 19:24:49浏览次数:51  
标签:语句 varchar DEFAULT setString 255 limit NULL 优化 pstmt

准备工作

创建一张测试表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `role` varchar(255) DEFAULT NULL,
  `d_1` varchar(255) DEFAULT NULL,
  `d_2` varchar(255) DEFAULT NULL,
  `d_3` varchar(255) DEFAULT NULL,
  `d_4` varchar(255) DEFAULT NULL,
  `d_5` varchar(255) DEFAULT NULL,
  `d_6` varchar(255) DEFAULT NULL,
  `d_7` varchar(255) DEFAULT NULL,
  `d_8` varchar(255) DEFAULT NULL,
  `d_9` varchar(255) DEFAULT NULL,
  `d_10` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `user_name` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=3761001 DEFAULT CHARSET=utf8mb3;

SET FOREIGN_KEY_CHECKS = 1;

结构如下

image

往表里面插入3760000条数据

public class BatchInsertDb {
    public static void main(String[] args) throws Exception {
        //插入数据库
        Class.forName("com.mysql.cj.jdbc.Driver");
        String url="jdbc:mysql://localhost:3306/test_mysql?characterEncoding=utf8&serverTimezone=UTC&useSSL=false";
        String username="root";
        String password="wl990922";
        Connection conn = DriverManager.getConnection(url, username, password);

        String sql = "insert into user(username,password,address,role,d_1,d_2,d_3,d_4,d_5,d_6,d_7,d_8,d_9,d_10)values(?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
        PreparedStatement pstmt = conn.prepareStatement(sql);
        for (int i = 0; i < 1000; i++) {
            pstmt.setString(1, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(2, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(3, "北京");
            pstmt.setString(4, "admin" + i);
            pstmt.setString(5, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(6, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(7, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(8, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(9, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(10, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(11, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(12, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(13, UUID.randomUUID().toString().replace("-", ""));
            pstmt.setString(14, UUID.randomUUID().toString().replace("-", ""));
            pstmt.addBatch();

        }
        pstmt.executeBatch();
        pstmt.close();
        conn.close();
        System.out.println("insert to db");
    }
}

limit优化

问题

在我们准备好表和数据以后,我们可以使用sql进行分页查询。

以下是两条查询语句,都是取40条数据,但性能就相差很大。

#查询结果是0.001秒
select * from user limit 0,40
#查询结果是2.9秒左右(不同电脑的性能不一样)
select * from  user limit 3740000,40
探究

上面的第二条sql执行的步骤如下:

  • 从表中读取第N条数据添加到数据集中
  • 重复第一步直到N=3740000+40
  • 根据偏移量抛弃前面的3740000条数据,返回剩余的40条数据

​ 可以看到导致性能下降的原因是第二步,这前面的3740000条数据对本地查询没有任何意义,并且占用了大部分时间!

​ 首先我们要了解数据库并不是顺序的存储数据,一方面是因为计算机存储本身就是随机读写,另一方面是因为数据操作有很大的随机性,经过增删改查数据也会变得乱。

第一次优化(数据库中有自增的主键)

本次优化必须数据库中有自增的主键

select * from user where id > 3740000 limit 40

发现只用了0.002秒,这条sql语句是告诉数据库,我就要 3740000 条数据以后的40条数据。

第二次优化

对于没有自增主键的,只能以下sql优化了,username为索引列。

select * from user INNER JOIN (select username from user  LIMIT 3740000,40)b using (username)

以上是先用索引列来查询 limit防止全表扫描,然后左边查询右边的结果

标签:语句,varchar,DEFAULT,setString,255,limit,NULL,优化,pstmt
From: https://www.cnblogs.com/wlstudy09/p/16855543.html

相关文章