0

我有一个数据库

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'

这两个查询都可以给我 bookID,其中只有名称或位置出现。所以我的目标是消除所有的 'charnames' 元素,而 bookID 没有出现在 'locs' 中,反之亦然。我的方法是:

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

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

4

2 回答 2

3

使用 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 而言,“数千本书”完全没有问题。大表性能的关键是正确的索引。对于此处的查询,以下索引可能会有所帮助:

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);

多列索引的性能可能会更好。使用 进行测试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查询确保基本查询只执行一次。
  • INTERSECT仅选择bookids具有位置名称的特征。
  • 最后返回所有UNION ALL找到的位置。如果要修剪具有相同位置的重复项,请改用。SELECTUNION
  • 我订购bookid, position- 猜测这是需要的。
  • 添加了一个列what来标记位置的来源(位置或名称)。

进一步优化

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

如果这还不够快,请查看全文搜索

于 2012-04-05T23:36:40.597 回答
0

see如果它加快了操作,您可以使用 set to

>>> xxx = set([(1,'a'), (2,'b')])
>>> xxx
set([(1, 'a'), (2, 'b')])
>>> xxx = set([(1,'a'), (3,'c')])
>>> yyy
set([(1, 'a'), (3, 'c')])
>>> c = xxx.intersection(yyy)
>>> c
set([(1, 'a')])   # common between xxx and yyy
>>> xxx - c
set([(2, 'b')])
于 2012-04-05T22:42:37.583 回答