Mysql 如何在另一个表中存储*排序*选择结果?

Mysql 如何在另一个表中存储*排序*选择结果?,mysql,sql,innodb,Mysql,Sql,Innodb,在我的项目中,我经常需要将SELECT的结果存储在另一个表中,我们称之为resultset。原因是在web应用程序中动态显示大量行,同时根据需要仅加载小块 通常,这是通过以下查询完成的: SET @counter := 0; INSERT INTO resultsetdata SELECT "12345", @counter:=@counter+1, a.ID FROM sometable a JOIN bigtable b WHERE (a.foo = b.ba

在我的项目中,我经常需要将SELECT的结果存储在另一个表中,我们称之为resultset。原因是在web应用程序中动态显示大量行,同时根据需要仅加载小块

通常,这是通过以下查询完成的:

SET @counter := 0;
INSERT INTO resultsetdata
  SELECT "12345", @counter:=@counter+1, a.ID
    FROM sometable a
    JOIN bigtable b
      WHERE (a.foo = b.bar)
    ORDER BY a.whatever DESC;
固定的12345值只是一个值,用于标识作为一个整体的结果集以及每个查询的更改。第二列是递增索引计数器,用于允许直接访问结果中的特定行,ID列引用源数据表中的特定行

当应用程序需要一定范围的结果时,我只需将resultsetdata与源表连接以获取详细数据-这与上面的resultsetdata查询相对,后者可能需要2-3秒才能完成,这解释了我为什么需要这个中间表

SELECT查询本身与此问题无关

resultsetdata具有以下结构:

CREATE TABLE `resultsetdata` (
  `ID`      int(11) NOT NULL,
  `ContIdx` int(11) NOT NULL,
  `Value`   int(11) NOT NULL,
  PRIMARY KEY (`ID`,`ContIdx`)
) ENGINE=InnoDB;
这通常像一个符咒,但最近我们注意到,在某些情况下,结果的顺序是不正确的。这取决于查询本身,例如,添加DISTINCT是一个典型的原因,服务器版本和源表中包含的数据,因此我想可以说,使用这种方法行顺序是不可预测的。这可能取决于内部优化

然而,现在的问题是,我想不出任何能给我带来预期结果的替代方案

由于resultset可以获得数千行,因此在内存中加载所有数据然后手动插入是不可行的

有什么建议吗

编辑:如需进一步澄清,请查看以下查询:

DROP TABLE IF EXISTS test;
CREATE TABLE test (ID INT NOT NULL, PRIMARY KEY(ID)) ENGINE=InnoDB;
INSERT INTO test (ID) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);

SET @counter:=0;
SELECT "12345", @counter:=@counter+1, ID
  FROM test
  ORDER BY ID DESC;
这将产生预期的以下结果:

+-------+----------------------+----+
| 12345 | @counter:=@counter+1 | ID |
+-------+----------------------+----+
| 12345 |                    1 | 10 |
| 12345 |                    2 |  9 |
| 12345 |                    3 |  8 |
| 12345 |                    4 |  7 |
| 12345 |                    5 |  6 |
| 12345 |                    6 |  5 |
| 12345 |                    7 |  4 |
| 12345 |                    8 |  3 |
| 12345 |                    9 |  2 |
| 12345 |                   10 |  1 |
+-------+----------------------+----+
10 rows in set (0.00 sec)
如前所述,在某些情况下,我无法在此提供测试用例,很抱歉,这可能会导致类似的结果:

+-------+----------------------+----+
| 12345 | @counter:=@counter+1 | ID |
+-------+----------------------+----+
| 12345 |                   10 | 10 |
| 12345 |                    9 |  9 |
| 12345 |                    8 |  8 |
| 12345 |                    7 |  7 |
| 12345 |                    6 |  6 |
| 12345 |                    5 |  5 |
| 12345 |                    4 |  4 |
| 12345 |                    3 |  3 |
| 12345 |                    2 |  2 |
| 12345 |                    1 |  1 |
+-------+----------------------+----+

我并不是说这是一个MySQL错误,我完全理解我的方法目前提供了不可预测的结果。不过,我不知道如何调整它以获得可预测的结果。

这是因为插入记录时的排序顺序与检索记录时的顺序无关

检索它们时,将创建一个查询计划。如果SELECT语句中未指定ORDER BY,则订单将取决于生成的查询计划。这就是为什么它是不可预测的,添加DISTINCT可以改变顺序


解决方案是存储足够的数据,以便使用ORDERBY子句以正确的顺序检索它们。在您的情况下,您已通过a.whatever对数据进行排序。a.任何内容都可以存储在resultsetdata中吗?如果是这样,则可以按正确的顺序读取记录。

这是因为插入记录时的排序顺序与检索记录时的顺序无关

检索它们时,将创建一个查询计划。如果SELECT语句中未指定ORDER BY,则订单将取决于生成的查询计划。这就是为什么它是不可预测的,添加DISTINCT可以改变顺序


解决方案是存储足够的数据,以便使用ORDERBY子句以正确的顺序检索它们。在您的情况下,您已通过a.whatever对数据进行排序。a.任何内容都可以存储在resultsetdata中吗?如果是这样,那么您可以按正确的顺序读取记录。

也许您可以将select包装成另一个select:

SET @counter := 0;

INSERT INTO resultsetdata
  SELECT *, @counter := @counter + 1
  FROM (
      SELECT "12345", a.ID
      FROM sometable a
      JOIN bigtable  b
      WHERE a.foo = b.bar
      ORDER BY a.whatever DESC
  ) AS tmp
。。。但你仍然任由MySQL优化器的愚蠢摆布

这就是我对这个话题的所有发现,但我找不到一个可靠的保证:


也许您可以将选择包装成另一个选择:

SET @counter := 0;

INSERT INTO resultsetdata
  SELECT *, @counter := @counter + 1
  FROM (
      SELECT "12345", a.ID
      FROM sometable a
      JOIN bigtable  b
      WHERE a.foo = b.bar
      ORDER BY a.whatever DESC
  ) AS tmp
。。。但你仍然任由MySQL优化器的愚蠢摆布

这就是我对这个话题的所有发现,但我找不到一个可靠的保证:


订单怎么不正确?如中所示,最终的“id”没有按您希望的方式排序?您已经添加了一个计数器,您的意思是该计数器没有正确排序吗?如何选择,在该计数器上进行排序?总之,总的来说,这整件事感觉有点像一个手动实现的缓存系统。你确定你需要这个方法吗?您能否更快地将结果保存到某种真正的缓存系统中,或者更新sometable和bigtable,这样就不会花费那么多秒?您能否提供正确排序的结果和错误排序的结果?我的意思是,在某些情况下,当在控制台上执行SELECT而不执行INSERT INTO时,您会看到ContIdx按降序排列。是的,这在某种程度上与缓存系统有关,但我不认为将大量数据加载到内存中是更好的解决方案。这个问题适用于包含大量已获取数据的各种查询/表,因此我无法进一步优化SELECT查询,也就是说,当用户浏览数据时,我无法一次又一次地进行优化。此外,我需要一些东西
因为表中不断地填充着数据。这就是关系数据库的工作原理。表中的行未排序,请将它们想象成篮子中的球。确保特定顺序的唯一方法是使用order by。@hyЛö:添加了@a_horse_,其名称为“correct”,但可以使用唯一的递增索引来存储行的顺序,在我的例子中,该索引将为ContIdx。顺序如何不正确?如中所示,最终的“id”没有按您希望的方式排序?您已经添加了一个计数器,您的意思是该计数器没有正确排序吗?如何选择,在该计数器上进行排序?总之,总的来说,这整件事感觉有点像一个手动实现的缓存系统。你确定你需要这个方法吗?您能否更快地将结果保存到某种真正的缓存系统中,或者更新sometable和bigtable,这样就不会花费那么多秒?您能否提供正确排序的结果和错误排序的结果?我的意思是,在某些情况下,当在控制台上执行SELECT而不执行INSERT INTO时,您会看到ContIdx按降序排列。是的,这在某种程度上与缓存系统有关,但我不认为将大量数据加载到内存中是更好的解决方案。这个问题适用于包含大量已获取数据的各种查询/表,因此我无法进一步优化SELECT查询,也就是说,当用户浏览数据时,我无法一次又一次地进行优化。此外,我需要一些静态的东西,因为表中不断地填充着数据。这就是关系数据库的工作方式。表中的行未排序,请将它们想象成篮子中的球。确保特定顺序的唯一方法是使用order by。@hyЛö:添加了@a_horse_,其名称为“no_name:correct”,但可以使用唯一的递增索引来存储行的顺序,在我的例子中,该索引是ContIdx。不幸的是,否,我无法在resultsetdata中存储a.whatever,因为我也可能在多个列上使用ORDER BY,并且排序列的类型并不总是相同的。除此之外,这是一个框架的一部分,它甚至不知道真正的查询是关于什么的。不幸的是,不,我不能在resultsetdata中存储a.whatever,因为我也可能在多个列上使用ORDER BY,并且排序列的类型并不总是相同的。除此之外,这是一个框架的一部分,它甚至不知道真正的查询是关于什么的。棒极了:-我不希望优化器会尝试优化外部选择,尽管祈求好运。也许你应该从真正的专家那里找到一些解释,比如Quassnoi@or的旧博客,或者你发现的任何东西:简单而且有效。棒极了:-我不希望优化器会尝试优化外部选择,尽管祈求好运。也许你应该从真正的专家那里找到一些解释,比如Quassnoi@or的旧博客,或者你找到的任何东西: