我有一个显示网络通讯的网页。目前有1622页。我需要显示当前的漫画页面(我有它的ID),以及指向第一页,上一页,下一页和最后一页的链接。排序也是非常重要的(由于奇怪的数据库设计有很长的ORDER BY - 传统的东西),所以我不能做“ID = 1”之类的东西。
所以,问题很简单 - 我知道记录的ID。我进行了SELECT ... FROM ... WHERE ... ORDER BY ...
查询,想要检索第一条记录,最后一条记录,具有我所知道ID的记录,以及具有已知ID的记录之前和之后的记录。
未过滤的查询返回超过1600行,并且每天都有一个新行。查询将每秒运行几次(有一个公平的读者群)。什么是最有效的方式?还有什么比天真的“获取所有行并过滤掉我需要的PHP代码”更好的东西吗?请注意,我知道我可以在PHP端缓存结果,但我想知道这里是否有一些与MySQL相关的优化。
已添加:一种解决方案是执行多个查询 - 每个查询需要一个查询。我应该说我知道它并想到更优雅的东西。
答案 0 :(得分:5)
为什么不以正确的方式添加顺序和排序的OrderedID列?您最初可以使用复杂查询填充,然后在添加新页面时保持更新。
如果不能修改现有表,您可以创建一个只有两列的新表,一个指向您的页表的FK,以及一个如上所述的OrderedID列?
这意味着对于任何页面ID = X,您将需要1,X-1,X,X + 1和Max() - 只有Max()实际上需要一个查询,并且每天只会更改一次。其他人可以算一算。
答案 1 :(得分:0)
嗯..我认为这个问题可以用很少的逻辑来完成。如果ID是自动增量(这会使这超级简单),那么你真的可以使用基本算术。
SELECT count(comicId)
FROM comics;
//Get that answer in php
$low = 0; //this could be anything.
$high = count;
$one = (($high - $low) / 2) + ($low - 1);
$two = $one + 1;
$three = $two + 1;
SELECT *
FROM comics
WHERE comicId IN ($low, $high, $one, $two, $three);
$ low应该是什么的原因是你可以在这里和那里更新低,以使“旧”漫画......好吧......不那么老(如果这是有道理的)。因此,不是从0开始(有史以来第一个漫画),你可以从50,100,1000开始,等等。 :)
好的所以现在因为有这条信息(并不是所有的id都存在(0-1600)而且其中一些不相关)。
请记住,这不是最终解决方案,我只是编造一个。编程时有很多选择。请记住效率(如果需要)。
1:创建某种链接表,无论如何都要调用它,[相关通讯]有2个字段,所需漫画的id和自动增量字段。
2:除了相应的修改之外,做一些与上面相同的逻辑。
$low = 0; //this could be anything.
$high = count;
$one = (($high - $low) / 2) + ($low - 1);
$two = $one + 1;
$three = $two + 1;
SELECT C.*
FROM comics AS C
JOIN relevantcomics AS RC
ON RC.id = C.comicid
WHERE RC.autoId IN ($low, $high, $one, $two, $three);
只要漫画插入正确的顺序,这应该适合你!为什么这样做是因为auto字段只是放入一个单独的表中,然后从那里检索和连接。这样就不必更改现有数据,除非插入新漫画时,相关表格也必须更新。
答案 2 :(得分:0)
只有1600行,我认为根本没有任何效率问题,但是你实现了这一点。但我们假设您可能有16M行。
假设您的查询类似于:
SELECT ... FROM ... WHERE ...
ORDER BY colA ASC
, colB DESC
, ...
, colZ ASC
id
是唯一键,特定id
是@id
。
您可以在(colA, colB, ..., colZ)
上添加索引并尝试此操作:
( SELECT ... FROM ... WHERE ...
ORDER BY colA ASC
, colB DESC
, ...
, colZ ASC
LIMIT 1 --- to get the first row
)
UNION ALL
( SELECT ... FROM ... WHERE ...
AND (colA, colB, ..., colZ)
< ( SELECT colA, colB, ..., colZ
FROM ...
WHERE id = @id )
ORDER BY colA DESC --- order reversed
, colB ASC --- order reversed
, ...
, colZ DESC --- order reversed
LIMIT 1 --- to get the previous row
)
UNION ALL
( SELECT ... FROM ... WHERE ...
AND (colA, colB, ..., colZ)
>= ( SELECT colA, colB, ..., colZ
FROM ...
WHERE id = @id )
ORDER BY colA ASC
, colB DESC
, ...
, colZ ASC
LIMIT 2 --- to get the row with @id and the next one
)
UNION ALL
( SELECT ... FROM ... WHERE ...
ORDER BY colA DESC --- order reversed
, colB ASC --- order reversed
, ... --- ...
, colZ DESC --- order reversed
LIMIT 1 --- to get the last row
)