Postgresql - 超过 3000 个值的 IN 子句优化

Posted

技术标签:

【中文标题】Postgresql - 超过 3000 个值的 IN 子句优化【英文标题】:Postgresql - IN clause optimization for more than 3000 values 【发布时间】:2021-02-23 09:36:12 【问题描述】:

我有一个应用程序,用户将上传一个包含超过 10,000 行的 excel 文件(.xlsx 或 .csv),其中包含要在数据库中查找的值的单列“partId”

我将读取 excel 值并将其存储在列表对象中,并将列表作为参数传递给 Spring Boot JPA 存储库 find 方法,该方法在内部构建 IN 子句查询:

                // Read excel file
                stream = new   ByteArrayInputStream(file.getBytes());
                wb = WorkbookFactory.create(stream);
                org.apache.poi.ss.usermodel.Sheet sheet = wb.getSheetAt(wb.getActiveSheetIndex());
                
                Iterator<Row> rowIterator = sheet.rowIterator();
                
                while(rowIterator.hasNext()) 
                    Row row = rowIterator.next();
                    Cell cell = row.getCell(0);
                    System.out.println(cell.getStringCellValue());
                    vinList.add(cell.getStringCellValue());
                
                
                //JPA repository method that I used
                  findByPartIdInAndSecondaryId(List<String> partIds);

我阅读了很多文章并在上述情况下遇到了相同的情况,即使用 IN 查询对于庞大的数据列表是低效的。

如何优化上述场景或编写新的优化查询?

另外,请告诉我是否有比上述代码sn-p更优化的读取excel文件的方式

这会很有帮助!!提前致谢!

【问题讨论】:

在 *** 上有一些使用 VALUES 连接而不是 in 的示例。你试过这个吗? @madflow,我试过了。我想知道是否有任何其他优化的方式来处理大量的值 @LaurenzAlbe,由于我将通过 API 从用户界面接收列表,因此我必须在应用程序和数据库之间移动大型列表。我不知道如何有效地通过列表 @LaurenzAlbe,恐怕我不清楚你的陈述:(。你能分享任何示例查询吗? 【参考方案1】:

如果列表真的很大,你永远不会像闪电一样快。

我看到了几个选项:

    正如您在问题中提到的那样,发送带有大量 IN 列表的查询。

    构造一个带有大 VALUES 子句的连接语句:

    SELECT ... FROM mytable
       JOIN (VALUES (42), (101), (43), ...) AS tmp(col)
          ON mytable.id = tmp.col;
    

    使用这些值创建一个临时表并与之连接:

    BEGIN;
    CREATE TEMP TABLE tmp(col bigint) ON COMMIT DROP;
    

    然后

    COPY tmp FROM STDIN; -- if Spring supports COPY
    

    INSERT INTO tmp VALUES (42), (101), (43), ...; -- if not
    

    然后

    ANALYZE tmp;  -- for good statistics
    SELECT ... FROM mytable
       JOIN tmp ON mytable.id = tmp.col;
    COMMIT;  -- drops the temporary table
    

哪一个最快最好根据您的案例反复试验来确定;我不认为可以说其中一种方法总是胜过其他方法。

一些注意事项:

解决方案 1. 和 2. 可能会产生非常大的语句,而解决方案 3. 可以分成更小的块。

解决方案 3. 很可能会更慢,除非列表真的很大。

【讨论】:

非常感谢!我会尝试所有这些方法并更新每个解决方案的状态。

以上是关于Postgresql - 超过 3000 个值的 IN 子句优化的主要内容,如果未能解决你的问题,请参考以下文章

postgresql 一个字段多个值的查询sql怎么写

一个表中有超过 3000 万个条目,执行一次选择计数需要 19 分钟

使用 PostgreSQL 更新前 N 个值

如何获取 postgresql 中的前 10 个值?

在 PostgreSQL 中返回表的用户定义函数

计算向量中每 n 个值的平均值