【问题标题】:SQL performance and alternative solutionSQL 性能和替代解决方案
【发布时间】:2019-11-23 16:04:08
【问题描述】:

我在 postgresql 数据库中关注了 2 个表 -

表1

  • col1_id(整数)
  • col2(文本)
  • col3(文本)
  • col4(文本)
  • col5(数字(1,0))
  • col6(数字(9,0))
  • col7_created_date(时间戳),
  • col8(文本)
CREATE UNIQUE INDEX col1_pkey ON table1 USING btree (col1_id),  

表2

  • col1_id(整数)
  • tab2_col2(文本)
  • tab3_col3(文本)
  • tab4_col4(整数)
  • tab5_col5(文本)
CREATE UNIQUE INDEX table2_pkey ON table2 USING btree (col1_id, tab3_col3)

FOREIGN KEY (col1_id) REFERENCES table1(col1_id) ON UPDATE RESTRICT ON DELETE RESTRICT

注意:从上面的表定义中,你会明白table1中的col1_id不仅是table2中的外键,还是table2中tab3_col3的一部分,支持1:Many关系。

这里的问题是 table1 有 10,00,000 行,而 table2 有 50,00,000 条记录。所以我的查询需要最少 5 秒的时间执行,这是我的查询 -

查询1:

SELECT * 
FROM table1 t1  
WHERE (col6 >= ?)  
  AND col5 IN (?)  
  AND (t1.col8 LIKE ? OR t1.col8 LIKE ?) 
ORDER BY col7_created_date DESC 
LIMIT 50

查询2:

SELECT COUNT(*) 
FROM table1 t1 
LEFT JOIN table2 t2 ON t2.col1_id = t1.col1_id 
WHERE t1.col7_created_date > ? 
  AND t2.tab4_col4 = ? 
  AND t2.tab3_col3 IN (?, ?) 
  AND a.tab2_col2 IN (?) 

理解要点:

  1. table2 应该有单独的 id 列作为主键以获得良好的性能,因为复合键会降低表中大量数据的性能。我可以解决这个问题。
  2. 我还可以从 table1 和 table2 中删除一些旧记录,但目前这不是我的选择。
  3. 在 Query1 中,我无法删除“col7_created_date DESC”,因为我只想要前 50 条记录,分页由业务逻辑控制。
  4. Query1 中的“LIKE”搜索是动态创建的,可以是 1 或 2..

问题:

  1. 如果我在 t1.col8 (Query1) 上创建索引会提高性能吗?如果是这样,是否有一种有效的方法来创建索引? (注意:t1.col8 是逗号分隔的文本,最多 4 个)
  2. 我应该做些什么来提高 Query1 和 Query2 的性能,我愿意更改 DDL。有什么建议吗?

【问题讨论】:

  • 请重新格式化您的问题。
  • 将逗号分隔的值存储在单个列中是一个真的开始的坏主意。在 Postgres 中,您至少应该使用正确的数组

标签: sql postgresql


【解决方案1】:

在整数字段上创建索引可提供更快的查找速度,但在您的情况下,b-tree 索引应该可以工作。此外,具有高度唯一性(重复值很少)的列也是获得索引的非常好的候选者。因此,如果 t1.col8 具有此属性,那么您最好继续在其上添加索引。如需更多参考,请查看this

【讨论】:

    【解决方案2】:

    运行解释分析以检查查询执行时间。explain

    查询一:

    SELECT * 
    FROM table1 t1  
    WHERE (col6 >= ?)  
      AND col5 IN (?)  
      AND (t1.col8 LIKE ? OR t1.col8 LIKE ?) 
    ORDER BY col7_created_date DESC 
    LIMIT 50
    

    您可以在 col6 和 col5 上添加复合索引。这些是数字列,因此会增加执行时间。而且您正在使用 IN 查询,这会使数据库变慢。避免使用 in 查询

    第二个查询也一样..

    创建不同的索引后,您可以运行此代码..

    explain analyze SELECT * 
    FROM table1 t1  
    WHERE (col6 >= ?)  
      AND col5 IN (?)  
      AND (t1.col8 LIKE ? OR t1.col8 LIKE ?) 
    ORDER BY col7_created_date DESC 
    LIMIT 50
    

    这会让你知道什么是需要时间的。

    您也可以粘贴有问题的内容,以便我建议更多索引。

    【讨论】:

      【解决方案3】:

      您的表有 100 万和 500 万条记录,对吗?索引访问真的没什么大不了的。

      索引在 query1 中对您没有任何作用。想想看,为了选择一条记录,优化器必须访问 col5 和 col6 和 col8 - 没有办法避免访问表,因为索引只是没有它们。不知道你从哪里得到这些关于复合索引的东西——你创建你的查询要求的任何索引,如果你查询想要 col5 和 col6 以及 col8 和 col1 和 col2——这就是你必须做的。因为您拥有的任何索引都比完全扫描表要好得多,这就是您现在正在做的事情。想想哪一列提供了最好的选择性,然后把它放在复合索引的首位。

      您的 Query2 是否也给您带来麻烦?它的执行计划是什么?

      【讨论】:

      • 您好,感谢您的贡献。您的回答不应包含其他问题。随意编辑您的答案。
      • 但我不明白原来的问题 - 我可以不要求澄清吗?
      猜你喜欢
      • 1970-01-01
      • 2017-08-27
      • 2015-07-07
      • 2011-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-13
      • 2016-10-24
      相关资源
      最近更新 更多