mysql - 排序和分页

标签 mysql sql hibernate spring-data querydsl

我的数据库 mysql 中有上千条记录,我使用分页只检索了 10 个结果。

当我在查询中添加 order by 时,它会变慢,但当我省略它时,查询运行得非常快。

我知道问题出在查询加载整个结果,对它们进行排序,然后获得 10 条记录。

我不使用索引,因为用于排序的列是一个 PK,我想如果我在 mysql 中没记错的话,会在每个主键上自动创建一个索引

  1. 为什么我的 PK 上的索引是我要订购的列。 没用过?
  2. 是否有任何替代解决方案可以在不加载所有数据的情况下执行排序?
  3. 如何在表格的第一行而不是表格的末尾添加新插入的数据?

我的sql查询

    select distinct ...... order by appeloffre0_.ID_APPEL_OFFRE desc limit 10

和我的索引

mysql> show index from appel_offre;
+-------------+------------+--------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table       | Non_unique | Key_name           | Seq_in_index | Column_name         | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------------+------------+--------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| appel_offre |          0 | PRIMARY            |            1 | ID_APPEL_OFFRE      | A         |       13691 |     NULL | NULL   |      | BTREE      |         |               |
| appel_offre |          1 | appel_offre_ibfk_1 |            1 | ID_APPEL_OFFRE_MERE | A         |           2 |     NULL | NULL   | YES  | BTREE      |         |               |
| appel_offre |          1 | appel_offre_ibfk_2 |            1 | ID_ACHETEUR         | A         |           2 |     NULL | NULL   |      | BTREE      |         |               |
| appel_offre |          1 | appel_offre_ibfk_3 |            1 | USER_SAISIE         | A         |           2 |     NULL | NULL   | YES  | BTREE      |         |               |
| appel_offre |          1 | appel_offre_ibfk_4 |            1 | USER_VALIDATION     | A         |           4 |     NULL | NULL   | YES  | BTREE      |         |               |
| appel_offre |          1 | ao_fk_3            |            1 | TYPE_MARCHE         | A         |           2 |     NULL | NULL   | YES  | BTREE      |         |               |
| appel_offre |          1 | ao_fk_5            |            1 | USER_CONTROLE       | A         |           2 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------------+------------+--------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
7 rows in set (0.03 sec)

解释命令中没有选择索引:

+----+-------------+---------------+--------+-------------------------------------+--------------------+---------+----------------
| id | select_type | table         | type   | possible_keys                       | key                | key_len | ref
+----+-------------+---------------+--------+-------------------------------------+--------------------+---------+----------------
|  1 | SIMPLE      | appeloffre0_  | ALL    | NULL                                | NULL               | NULL    | NULL

更新解决方案

问题出在distinct,当我删除它时,查询最终使用了索引。

最佳答案

因为您已经在“USER_VALIDATION”上使用了索引,所以 MySQL 不会改用 ID 索引。

尝试重建 USER_VALIDATION 索引以也包含 ID:

CREATE UNIQUE INDEX appel_offre_ibfk_4 ON appel_offre (USER_VALIDATION, ID);

更新

记录所有 Hibernate 查询,提取慢速查询并使用 EXPLAIN在数据库控制台中了解 MySQL 为此查询选择的执行计划。即使您有索引,数据库也可能会使用 FULL TABLE SCAN,因为索引太大而无法放入内存。尝试按照说明给它一个提示 in this post .

根据 MySQL ORDER BY optimization documentation你应该:

要提高 ORDER BY 速度,请检查是否可以让 MySQL 使用索引而不是额外的排序阶段。如果这不可能,您可以尝试以下策略:

• Increase the sort_buffer_size variable value.

• Increase the read_rnd_buffer_size variable value.

• Use less RAM per row by declaring columns only as large as they need to be to hold the values stored in them. For example, CHAR(16) is better than CHAR(200) if values never exceed 16 characters.

• Change the tmpdir system variable to point to a dedicated file system with large amounts of free space. The variable value can list several paths that are used in round-robin fashion; you can use this feature to spread the load across several directories. Paths should be separated by colon characters (“:”) on Unix and semicolon characters (“;”) on Windows, NetWare, and OS/2. The paths should name directories in file systems located on different physical disks, not different partitions on the same disk.

还要确保 DISTINCT 不会否决您的索引。尝试删除它,看看是否有帮助。

关于mysql - 排序和分页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27657636/

相关文章:

php - 两个顺序 SELECT 表的最佳方法

mysql - 加入一个表并从这个新表中计算百分比

php - 使用 AJAX 和 PHP 更新 MySQL

php - 我找到了一个 $_GET ['var' ] == 一个 SQL 语句 - 有什么风险?

java - JPA/Hibernate - 不需要的部分回滚和 session 处理

mysql - 在最小化冗余方面,像 MySQL 和 H2 这样的数据库有多聪明?

c# - 如何构建这个允许多个用户/对象的加密系统

java - 使用Spring JdbcTemplate提取一个字符串

java - 如何使用 Spring 和 Hibernate 调用具有两个参数的存储过程

hibernate - 存储过程更新数据库后从数据库重新加载对象,而不是缓存?