2017-10-10 111 views
1

的唯一性在某些情况下(大数据集存储在表中),我需要检查Postgres表的字段的唯一性。检查表字段postgres

为了简化的目的,让我们说,我有如下表:

id | name 
-------------- 
1 | david 
2 | catrine 
3 | hmida 

,我要检查的字段名称的唯一性;其结果将是真正的 到目前为止,我设法使用类似的代码如下:

select name, count(*) 
from test 
group by name 
having count(*) > 1 

放记住,我有一个大的数据集,所以我更喜欢这个由RDBMS来处理,而不是获取的数据通过适配器(例如psycopg2)。 所以我需要尽可能地优化。任何书呆子的想法?

+0

你的代码不工作(它看起来应该)?什么是问题? –

+0

查询需要2分钟的1000万行数据集,我需要更快的速度。 –

+0

与您的查询数据在数据库端进行处理 - 而不是psycopg2 –

回答

1

这将是可能更快,但不太可靠的解决方案:

t=# create table t (i int); 
CREATE TABLE 
t=# insert into t select generate_series(1,9,1); 
INSERT 0 9 
t=# insert into t select generate_series(1,999999,1); 
INSERT 0 999999 
t=# insert into t select generate_series(1,9999999,1); 
INSERT 0 9999999 

现在查询:

t=# select i,count(*) from t group by i having count(*) > 1 order by 2 desc,1 limit 1; 
i | count 
---+------- 
1 |  3 
(1 row) 

Time: 7538.476 ms 

现在从统计检查:

t=# analyze t; 
ANALYZE 
Time: 1079.465 ms 
    t=# with fr as (select most_common_vals::text::text[] from pg_stats where tablename = 't' and attname='i') 
    select count(1),i from t join fr on true where i::text = any(most_common_vals) group by i; 
    count | i 
    -------+-------- 
     2 | 94933 
     2 | 196651 
     2 | 242894 
     2 | 313829 
     2 | 501027 
     2 | 757714 
     2 | 778442 
     2 | 896602 
     2 | 929918 
     2 | 979650 
     2 | 999259 
    (11 rows) 

    Time: 3584.582 ms 

,最后只是检查如果不是uniq只存在一个最频繁的值:

统计在表上收集后
t=# select count(1),i from t where i::text = (select (most_common_vals::text::text[])[1] from pg_stats where tablename = 't' and attname='i') group by i; 
count | i 
-------+------ 
    2 | 1540 
(1 row) 

Time: 1871.907 ms 

更新

pg_stats数据modifyed。因此,您有机会获得数据分配方面的最新汇总统计信息。在我的实例样本:

t=# delete from t where i = 1540; 
DELETE 2 
Time: 941.684 ms 
t=# select count(1),i from t where i::text = (select (most_common_vals::text::text[])[1] from pg_stats where tablename = 't' and attname='i') group by i; 
count | i 
-------+--- 
(0 rows) 

Time: 1876.136 ms 
t=# analyze t; 
ANALYZE 
Time: 77.108 ms 
t=# select count(1),i from t where i::text = (select (most_common_vals::text::text[])[1] from pg_stats where tablename = 't' and attname='i') group by i; 
count | i 
-------+------- 
    2 | 41377 
(1 row) 

Time: 1878.260 ms 
当然

如果依靠更多的则只是一个最频繁的值,失败机会减少,但再次 - 这种方法依赖于统计数据“新鲜”。

+0

你能详细说明为什么你用'不可靠'来描述你的解决方案,在这种情况下这是不可靠的。非常感谢。 –