搜索数据库表以确定列表中看不到的文件名

问题描述

我正在处理磁盘上的平面文件,并且需要确保我从未两次处理同一文件。每个处理文件文件名都存储在postgresql DB中,在下一次迭代中,我需要确定磁盘上看不见的文件并进行处理,即。我需要确定磁盘上文件名和数据库文件名的设置差异。

当前,我的方法是从磁盘上的文件名创建CTE,并将其加入可见文件名表。磁盘上的文件列表很大并且不断变化,并且处理速度也在变慢。

这是当前查询

WITH input(filename) AS (VALUES ${filenames.joinToString { "(?)" }})
SELECT input.filename FROM input 
LEFT JOIN my_table pm ON input.filename ILIKE pm.filename
WHERE pm.filename IS NULL

${filenames.joinToString { "(?)" }}扩展为(?),(?),(?)之类的东西,具体取决于文件名参数的数量

我该如何加快此过程?

要做的一件事是在文件名列上添加一个索引。正确的选择是哪种索引?

解决方法

由于您使用的是ILIKE,因此我不会在pm.filename上放置索引,而是在LOWER(pm.filename)上放置索引。这应该允许您删除ILIKE,而选择性能更高的LIKE。这也意味着您只能使用简单的B-tree index,因为它可以与LIKE一起正常工作。如果您使用通配符,LIKE很有用,但如果不使用通配符,请使用常规的=-等于。

最后,查询优化器很有可能已经对该查询做了很多工作,但是我建议您查看此查询的EXPLAIN (ANALYSE)输出。我有一些改进的建议,但是对于它们是否会有所帮助或都将归结为相同的查询计划一无所知。这完全取决于您!


这将第一个查询的结果放在第一个列表中,并从第二个查询的结果中删除所有匹配项。缺点是返回的文件名是小写的。

SELECT LOWER(filename)
FROM (VALUES ${filenames.joinToString { "(?)" }}) AS input(filename)
EXCEPT ALL (SELECT LOWER(filename) FROM my_table pm)

此查询没有此缺点,它只返回my_table中不匹配的所有文件名。

SELECT filename
FROM (VALUES ${filenames.joinToString { "(?)" }}) AS input(filename)
WHERE NOT EXISTS (
  SELECT
  FROM my_table pm
  WHERE LOWER(pm.filename) = LOWER(input.filename)
)

最后一个查询可能与此等效,但是为了完整起见,我将其添加。

SELECT filename
FROM (VALUES ${filenames.joinToString { "(?)" }}) AS input(filename)
WHERE LOWER(filename) NOT IN (
  SELECT LOWER(pm.filename)
  FROM my_table pm
)