加速大型PostgreSQL数据库中的SELECT查询响应(2.5亿行)

时间:2016-09-17 00:11:25

标签: sql postgresql postgresql-performance

使用PostgreSQL,我有一个包含以下4个属性的大约2.5亿行的非常大的表:

CREATE TABLE public.sim_values_english
(
  id bigint NOT NULL DEFAULT nextval('sim_values_english_id_seq'::regclass),
  word1 character varying(255),
  word2 character varying(255),
  sim_value double precision,
  CONSTRAINT pk_sim_values_english PRIMARY KEY(id)
)

我尝试使用以下SELECT查询根据定义的sim_valueword1选择word2属性:

(假设我有2个单词:X和Y,其中X或Y可以属于word1或word2)

SELECT sim_value
From public.sim_values_english
Where (word1='X' or word2='X') and (word1='Y' or word2='Y') and (word1!=word2)

平均需要1~1.5分钟才能返回真正很长的sim_value!将整个表存储在内存中非常昂贵,因为它的重量超过10 GB。

如何加快此查询?你有什么建议吗?

PS:word1word2永远不会相同,所以如果是1个案例:word1是X word2是Y,那么那里不存在word1为Y word2为X的另一行!

注意:我搜索了类似的主题,但没有一个解决了这个问题。感谢您的理解

谢谢

3 个答案:

答案 0 :(得分:4)

首先,如果您还没有,我会确保存在以下索引:

CREATE INDEX ON sim_values_english(word1, word2);

然后我会尝试以下查询:

SELECT sim_value
FROM sim_values_english
WHERE word1='X' AND word2='Y'
UNION ALL
SELECT sim_value
FROM sim_values_english
WHERE word1='Y' AND word2='X'

答案 1 :(得分:2)

所以你必须在这两个字段上创建索引

CREATE INDEX word1_word2_idx ON sim_values_english (word1, word2);

然后您的查询非常基本

SELECT sim_value
FROM sim_values_english
WHERE (word1='X' AND word2='Y') OR (word1='Y' AND word2='X')

答案 2 :(得分:0)

开始存储,但仅引用,这将使桥接表更精简:

CREATE TABLE words_english
        ( word_id integer -- or: serial if you want
                NOT NULL PRIMARY KEY
        , word varchar UNIQUE
        );

CREATE TABLE sim_values_english
        ( word_id integer NOT NULL references words_english (word_id)
        , other_id integer NOT NULL references words_english (word_id)
        , sim_value DOUBLE PRECISION NOT NULL DEFAULT 0.0
        , PRIMARY KEY (word_id, other_id)
        );

CREATE UNIQUE INDEX ON sim_values_english(other_id,word_id);

您的查询现在可以重新命名为:

SELECT sim_value
FROM sim_values_english v
JOIN words_english one ON v.word_id = one.word_id
JOIN words_english two ON v.other_id = two.word_id
WHERE one.word IN ('X' ,'Y')
AND two.word IN ( 'X', 'Y' )
AND v.word_id <> v.other_id
        ;

(或使用视图来模拟旧表)

检查这个较旧的答案,了解表中squeezing out脂肪重复列的配方。