订购和分页

时间:2014-12-26 13:12:18

标签: mysql sql hibernate spring-data querydsl

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

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

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

我不使用索引,因为用于订单的列是PK,我认为如果我在mysql中没有错误,则会在每个主键上自动创建索引

  1. 为什么我的PK上的索引是我订购的列。 没用过?
  2. 有没有其他替代解决方案可以在不加载所有数据的情况下执行排序?
  3. 如何在表的第一行而不是表的末尾添加新插入的数据?
  4. 我的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)
    

    在explain cmd中没有选择索引:

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

    更新解决方案

    问题来自distinct,当我删除它时,查询最终使用索引。

2 个答案:

答案 0 :(得分:3)

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

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

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

更新

记录所有Hibernate查询,解压慢查询并在db控制台中使用EXPLAIN来了解MySQL为此查询选择的执行计划。即使有索引,db也可能使用FULL TABLE SCAN,因为索引太大而无法容纳到内存中。尝试按照in this post所述给它一个提示。

根据MySQL ORDER BY optimization documentation你应该:

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

  

•增加sort_buffer_size变量值。

     

•增加read_rnd_buffer_size变量值。

     

•通过仅根据需要声明列来减少每行RAM的使用   要保存存储在其中的值。例如,CHAR(16)是   如果值不超过16个字符,则优于CHAR(200)。

     

•将tmpdir系统变量更改为指向专用文件   具有大量可用空间的系统。变量值可以列出   以循环方式使用的几条路径;你可以用它   功能将负载分散到多个目录中。路径应该是   在Unix和分号字符上用冒号字符(“:”)分隔   (“;”)在Windows,NetWare和OS / 2上。路径应该命名目录   在位于不同物理磁盘上的文件系统中,没有什么不同   同一磁盘上的分区。

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

答案 1 :(得分:2)

  1. 为您订购的列添加索引。
  2. 您无法在表格的开头添加行,就像您无法在表格的末尾添加行一样。数据库表是多集的。根据定义,Multisets是无序集合。 第一个元素最后一个元素的概念对于多重集合没有任何意义。