我有一个
的数据库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'的所有元素,其中bookIDs不会出现在'locs'中,反之亦然。我的方法是:
for cnameTuple in charnames:
~if cnameTuple[0] in locsIDs:
~~continue
~del(cname)
我为locs中的元组做了相应的循环 遗憾的是,该算法需要大量时间。有没有办法更快地执行此任务?
答案 0 :(得分: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';
only retrieve the data you need from the database server通常是一个好主意,而不是在您的应用中获取过多的数据和过滤。数据库引擎针对过滤和排序进行了优化。你很难在你的应用程序中与之匹配。
请注意我如何使用所有小写名称。阅读manual about identifiers。
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;
WITH
query)确保基本查询仅执行一次。INTERSECT
仅挑选具有和位置的bookids
。SELECT
中的UNION ALL
会返回找到的所有位置。如果您想修剪具有相同位置的重复项,请使用UNION
。bookid, position
命令 - 猜测这就是所需要的。what
来标记某个职位的来源(位置或名称)。如果每本书的搜索字词多次,您可以通过为(bookid, term)
创建包含不同条目的辅助表来大大加快搜索速度。在两列上创建多列主索引,在term
上创建另一列。为位置创建一个这样的表,为名称创建另一个表。如果需要的话,让它们与触发器保持同步,但我认为书籍的内容没有太大变化。将简化和加快CTE。
如果仍然不够快,请查看Full Text Search。
答案 1 :(得分:0)
如果加速操作,您可以使用设置为see
>>> 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')])