【问题标题】:Speeding up SELECT query response in large PostgreSQL Database (250 million rows)加快大型 PostgreSQL 数据库(2.5 亿行)中的 SELECT 查询响应
【发布时间】:2016-09-18 02:24:04
【问题描述】:

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

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 查询根据定义的 word1word2 选择 sim_value 属性:

(假设我有 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)。

如何加快查询速度?你有什么建议?

P.S.:word1word2 永远不会相同,所以如果对于 1 种情况:word1 是 X 并且 word2 是 Y,那么不存在 @987654333 的另一行@ 是 Y 并且 word2 是 X!

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

谢谢

【问题讨论】:

  • 你对 word1 和 word2 有索引吗?
  • @Sylwit 不,我不知道,因为这些属性特定于该表,并且独立于我数据库中的所有其他表。
  • “这些属性特定于该表并且独立于我数据库中的所有其他表”这一事实与您是否应该对它们建立索引的问题绝对无关。
  • 在答案底部创建索引并以stackoverflow.com/questions/39292297/…的值加入

标签: sql postgresql postgresql-performance


【解决方案1】:

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

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'

【讨论】:

  • 你能解释一下 UNION,因为当你只能用一个 SELECT 查询时,它会执行 2 次 SELECT 查询?
  • @Sylwit 这个想法是 postgres 无论如何都必须扫描索引两次,所以至少可以避免创建位图索引和合并位图。
【解决方案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')

【讨论】:

    【解决方案3】:

    首先存储单词,而只存储对它们的引用,这将使桥接表更精简:

    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 肥胖、重复的列的配方。

    【讨论】:

      猜你喜欢
      • 2018-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-24
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多