// Inspired by:
// https://www.sqlite.org/forum/forumpost/e2216583a4
// https://stackoverflow.com/a/24511461/7776828
// Simulate N autoincrement stable ids
// (Avoid rowid which is unstable)
const max = 20;
const a = Array();
for (let id = 0; id < max; ++id) {
a.push({id});
}
console.log(a);
// Order the results by random
const orderByRandom = ({a, seed}) => {
// For each result,
// Use sin(id + seed) to get a stable random score
const randomScored = a.map(x => {
return { ...x, score: Math.sin(x.id + seed) }
});
// Sort by the random score
randomScored.sort((a,b) => a.score - b.score);
return randomScored;
}
// Used for generating the seed
const random = () => 1 + Math.floor(Math.random() * Number.MAX_SAFE_INTEGER - 1);
let seed;
seed = random(); // seed #1
console.log(orderByRandom({a, seed}));
console.log(orderByRandom({a, seed})); // Stable, can paginate
seed = random(); // seed #2
console.log(orderByRandom({a, seed})); // New order because new seed
5条答案
按热度按时间o2gm4chl1#
hs1rzwqc2#
使用random():
**编辑(通过QOP):**由于SQLite Autoincrement ed列上的文档指出:
只要您从不使用最大ROWID值,也从不删除表中具有最大ROWID的条目,上述常规ROWID选择算法 * 将生成单调递增的唯一ROWID *。如果您删除过行,则在创建新行时可能会重新使用以前删除的行中的ROWID。
只有在没有
INTEGER PRIMARY KEY AUTOINCREMENT
列的情况下才是这样(使用INTEGER PRIMARY KEY
列时也能正常工作)。无论如何,这应该更易移植/更可靠:ROWID
、_ROWID_
和OID
都是SQLite内部行ID的别名。inn6fuwd3#
已解决:
um6iljoc4#
要获得更好的性能,请在SQLite中使用此命令:
这也适用于MySQL,它运行得更快,因为SQL引擎首先将行的投影字段加载到内存中,然后对它们进行排序,这里我们只加载行的id字段并随机排序,然后我们得到其中的X个,并找到默认索引的这X个id的整行。
cbjzeqam5#
目标是获得随机结果(无限滚动),同时能够用SQL对结果分页(
LIMIT a,b
),这需要一个可预测的结果(伪随机,又名PRNG)。SIN(id + seed)
似乎是RANDOM(seed)
的一个很好的替代品。请考虑这个完全用JS编写的演示,它使用
SIN(id + seed)
评分模拟ORDER BY
子句: