获得这种倾斜概率的一种非常简单有效的方法是平方random()
(或采取random()^3
更强的影响..)。
在这个前提下,这个函数会产生一个“完美的结果”:
CREATE OR REPLACE FUNCTION f_del()
RETURNS void AS
$func$
DECLARE
_del_pct CONSTANT real := 0.8; -- percentage to delete
_min int; -- minimum i in table
_span int; -- diff. to maximum i
_ct int; -- helper var.
_del_target int; -- number rows to be deleted
BEGIN
SELECT INTO _min, _span, _del_target
min(i), max(i) - min(i), (count(*) * _del_pct)::int FROM tbl;
LOOP
DELETE FROM tbl t
USING (
SELECT DISTINCT i
FROM (
SELECT DISTINCT _min + (_span * random()^2)::int AS i -- square it
FROM generate_series (1, _del_target * 3) -- good estimate for 80%
) num -- generate approx. more than enough numbers
JOIN tbl USING (i)
LIMIT _del_target -- prohibit excess dynamically
) x
WHERE t.i = x.i;
GET DIAGNOSTICS _ct = ROW_COUNT;
_del_target := _del_target - _ct;
EXIT WHEN _del_target <= 0;
END LOOP;
END $func$ LANGUAGE plpgsql;
称呼:
SELECT f_del();
->SQLfiddle
这应该可以完美地工作
- 数字空间中有或没有间隙
(适用_del_target
于count()
代替_span
,所以这也有效。)
- 具有任何最小和最大数量
- 任意数量的行
线
JOIN tbl USING (i)
.. 仅当您对 . 有很多差距或初始估计错误时才真正有用generate_series()
。可以为手头的情况移除以获得更快的速度(并且仍然是准确的结果)。
如果您generate_series()
仔细选择初始限制,该函数将根本不会循环。
我认为可以安全地假设我不需要告诉您如何进一步概括这一点以使用动态表名或百分比。
它有点类似于这个答案:
Best way to select random rows PostgreSQL
对于这种情况,简单的 SQL 命令会运行得更快一些:
DELETE FROM tbl t
USING (
SELECT DISTINCT (1000000 * random()^2)::int AS i
FROM generate_series (1, 2130000)
) x
WHERE t.i = x.i;