2013-04-10 35 views
1

在我的项目中,我经常需要将SELECT的结果存储在另一个表中(我们称之为“结果集”)。原因是在Web应用程序中动态显示大量行,同时根据需要只加载小块。如何在另一个表中存储* sorted * SELECT结果?

典型地,这是通过查询完成象这样的:

SET @counter := 0; 
INSERT INTO resultsetdata 
    SELECT "12345", @counter:[email protected]+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是典型原因),服务器版本和源表中包含的数据,所以我猜可以这样说,行顺序是不可预测的与此方法。可能取决于内部优化。

但是,问题现在,我想不出任何替代解决方案,给我预期的结果。

由于结果集可能会获得数千行,因此将所有数据加载到内存中,然后手动执行它是不可行的。

有什么建议吗?


编辑:为了进一步澄清,看看这些查询:

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:[email protected]+1, ID 
    FROM test 
    ORDER BY ID DESC; 

这将产生以下结果为 “预期”:

+-------+----------------------+----+ 
| 12345 | @counter:[email protected]+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:[email protected]+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错误,我完全理解,我的方法目前提供不可预知的结果。不过,我不知道如何调整这个来获得可预测的结果。

+0

怎样的顺序不正确的?如在最后的'身份证'没有排序你想要它是什么?你已经添加了一个计数器,你的意思是计数器没有正确分类?你如何选择,在柜台上排序?无论如何,总的来说,这整个事情感觉有点像手动实现的缓存系统。你确定你甚至需要这种方法吗?难道你不能更快地将结果保存到某种真正的缓存系统中,或者更新'sometable'和'bigtable',这样不需要很多秒钟? – Nanne 2013-04-10 08:41:35

+0

你能提供正确的'ORDER'ed结果和错误的ORDER'ed一个吗?而你的'SELECT'只是确定的。 – 2013-04-10 08:45:55

+0

我的意思是,在某些情况下,当在控制台上执行不带'INSERT INTO'的'SELECT'时,会看到'ContIdx'按**递减顺序。是的,这与缓存系统有些相关*,但我不认为将大量数据加载到内存(?)是更好的解决方案。这个问题适用于包含大量获取数据的各种查询/表格,所以我无法进一步优化SELECT查询(即,当用户浏览数据时,我无法一次又一次地进行查询)。此外,我需要somthing * static *,因为表格会连续填充数据。 – 2013-04-10 08:49:51

回答

1

也许你可以换到选择另一种选择:

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的优化器的哑的摆布。

这就是我发现这个话题,但我couln't发现很难保证:

Pure-SQL Technique for Auto-Numbering Rows in Result Set

http://www.xaprb.com/blog/2006/12/02/how-to-number-rows-in-mysql/

http://www.xaprb.com/blog/2005/09/27/simulating-the-sql-row_number-function/

+0

简单而有效。伟大的:-)我不指望优化器会尝试优化外部SELECT,尽管(手指交叉)。 – 2013-04-10 09:35:04

+0

也许你应该从真正的专家那里找到一些解释,比如Quassnoi @ http://explainextended.com/或http://www.xaprb.com/的旧博客条目,或者任何你发现的东西:) – biziclop 2013-04-10 09:38:16

3

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

当您检索它们时,将创建查询计划。如果在SELECT语句中没有指定ORDER BY,那么顺序将取决于生成的查询计划。这就是为什么它是不可预知的,并且添加DISTINCT可以改变顺序。

解决方案是存储足够的数据,您可以使用ORDER BY子句以正确的顺序检索它们。在你的情况下,你已经通过a.whatever命令你的数据。 a.whatever可以存储在resultsetdata中吗?如果是这样,那么你可以按照正确的顺序读出记录。

+0

不幸的是,我不能在'resultsetdata'中存储'a.whatever',因为我也可以在多个列上使用ORDER BY,排序的列并不总是相同的。除此之外,这是一个甚至不知道真正的查询是什么的框架的一部分。 – 2013-04-10 09:01:17

相关问题