python - 多条件有效查询

标签 python postgresql psycopg2

我有一个数据库

books          (primary key: bookID)
characterNames (foreign key: books.bookID) 
locations      (foreign key: books.bookID)

字符名称和位置的文本位置保存在相应的表中。
现在我想使用 psycopg2 编写一个 Python 脚本来查找给定字符名称和给定位置在书中的所有出现,两者都出现的地方。
目前,我执行 4 个查询:

SELECT bookID, position FROM characterNames WHERE name='XXX';
--> result is saved in list 'charnames'

SELECT DISTINCT bookID FROM characterNames WHERE name='XXX';
--> result is saved in list 'charnamesIDs'

SELECT bookID, position FROM locations WHERE locName='YYY';
--> result is saved in list 'locs'

SELECT bookID FROM locations WHERE locName='YYY';
--> result is saved in list 'locsIDs'

这两个查询都可以给我 bookIDs,其中只显示名称或位置。因此,我的目标是消除“charnames”的所有元素,其中 bookID 未出现在“locs”中,反之亦然。我的方法是:

for cnameTuple in charnames:  
~if cnameTuple[0] in locsIDs:  
~~continue  
~del(cname)

我为locs中的元组做了一个相应的循环。
不幸的是,这个算法需要很多时间。有没有办法更快地执行此任务?

最佳答案

如果使用 JOIN 查询,这可能会更快更简单
像这样:

SELECT b.*, c.position, l.position
FROM   books b
JOIN   characternames c USING (bookid)
JOIN   locations l USING (bookid)
WHERE  c.name = 'XXX'
AND    l.locname = 'YYY';

评论后的更多信息

对于像 PostgreSQL 这样旨在处理 数百万 的 RDBMS,“数千本书”根本不是问题。大表性能的关键是适当的indexes .对于此处的查询,以下索引可能会有所帮助:

CREATE INDEX books_bookid_idx ON books(bookid); -- a primary key will do, too

CREATE INDEX cn_bookid_idx ON characternames (bookid);
CREATE INDEX cn_name_idx ON characternames (name);

CREATE INDEX locations_bookid_idx ON locations (bookid);
CREATE INDEX locations_locname_idx ON locations (locname);

Multicolumn indexes可能表现得更好。用 EXPLAIN ANALYZE 测试,它将向您显示使用了哪些索引以及查询的速度。创建索引非常快,使用它们进行试验也很容易。只是不要保留不需要的索引。它们也有维护成本。


优化查询

think 我现在明白了,你在找什么。应该优化此查询以获取每个 bookid 的位置或名称的所有位置,但仅限于名称 位置出现在同一本书中的位置,并且没有每本书的更多详细信息:

WITH b AS (
    SELECT bookid
    FROM   characternames
    WHERE  name = 'XXX'
    GROUP  BY 1
    INTERSECT
    SELECT bookid
    FROM   locations
    WHERE  l.locname = 'YYY'
    GROUP  BY 1
    )
SELECT bookid, position, 'char' AS what
FROM   b
JOIN   characternames USING (bookid)
WHERE  name = 'XXX'
UNION  ALL
SELECT bookid, position, 'loc' AS what
FROM   b
JOIN   locations USING (bookid)
WHERE  locname = 'YYY'
ORDER  BY bookid, position;

要点

  • CTE (WITH query)确保基本查询只执行一次。
  • INTERSECT仅选择具有位置名称的 bookids
  • UNION ALL在最后的SELECT 中返回所有 找到的位置。如果您想修剪具有相同位置的重复项,请改用 UNION
  • 我按 bookid, position 排序 - 猜想这是需要的。
  • 添加了一列 what 来标记位置的来源(位置或名称)。

进一步优化

如果搜索字词在每本书中出现多次,您可以通过为(bookid, term)创建具有不同条目的辅助表来大大加快搜索速度。在两列上创建一个多列主索引,并在 term 上创建一个附加索引。为位置创建一个这样的表,为名称创建另一个表。如果需要的话,让它们与触发器保持同步,但我认为书籍的内容变化不大。将简化和加速 CTE。

如果仍然不够快,请查看 Full Text Search .

关于python - 多条件有效查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10036645/

相关文章:

python Mechanize 表单登录给出TypeError

python - Python 中 STRINGS 的 switch-case 语句

python - 这个 TensorFlow 示例实际上是如何更新权重来找到解决方案的

python - psycopg2.ProgrammingError : column "your name" does not exist

linux - 为 Postgres 中的 to_char 设置全局标准

python脚本读取三个csv文件并写入一个csv文件

postgresql - 为什么 pg_dump 忽略 .pgpass?

sql - 如何对两个不相关的表进行求和?

postgresql - 是否可以在没有Struct的情况下反序列化tokio_postgres行?

python - 在 Psycopg2 中高效地插入大量行