Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/349.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 具有多个条件的有效查询_Python_Postgresql_Psycopg2 - Fatal编程技术网

Python 具有多个条件的有效查询

Python 具有多个条件的有效查询,python,postgresql,psycopg2,Python,Postgresql,Psycopg2,我有一个数据库 books (primary key: bookID) characterNames (foreign key: books.bookID) locations (foreign key: books.bookID) 字符名称和位置的文本位置保存在相应的表中。 现在,我想使用psycopg2编写一个Python脚本,以查找书籍中给定字符名和给定位置的所有匹配项,这两者都出现在书籍中。 目前,我执行4个查询: SELECT bookID, posit

我有一个数据库

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中的元组进行了相应的循环。

不幸的是,这个算法需要很多时间。有没有办法更快地执行此任务?

如果设置为
可以加快操作速度,请参见

>>> 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')])

如果设置为
可加快操作速度,则可以使用该设置,请参见

>>> 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')])

通过使用联接进行查询,可以更快、更简单。
大概是这样的:

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);
也许表现会更好。通过测试,它将显示使用了哪些索引以及查询的速度。创建索引非常快,使用它们进行实验很容易。只是不要保留你不需要的索引。它们也有维护费用


优化查询 我想我现在明白你在找什么了。应优化此查询,以获得每个
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;
要点
  • 确保基本查询只执行一次
  • 仅拾取同时具有位置和名称的图书ID
  • 最后一个
    选择中的返回所有找到的位置。如果要修剪相同位置的重复项,请改用
    UNION
  • 我按
    bookid,position
    -猜测这是需要的
  • 添加了一列
    what
    来标记位置的来源(位置或名称)

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


如果这仍然不够快,请查看。

使用联接进行查询时,这可能会更快、更简单。
大概是这样的:

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);
也许表现会更好。通过测试,它将显示使用了哪些索引以及查询的速度。创建索引非常快,使用它们进行实验很容易。只是不要保留你不需要的索引。它们也有维护费用


优化查询 我想我现在明白你在找什么了。应优化此查询,以获得每个
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;
要点
  • 确保基本查询只执行一次
  • 仅拾取同时具有位置和名称的图书ID
  • 最后一个
    选择中的返回所有找到的位置。如果要修剪相同位置的重复项,请改用
    UNION
  • 我按
    bookid,position
    -猜测这是需要的
  • 添加了一列
    what
    来标记位置的来源(位置或名称)

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


如果这仍然不够快,请查看。

您好,很抱歉我还没有回复。使用JOIN是我的第一种方法,但有人告诉我这太昂贵了。我正在研究一个由数千本书组成的语料库,所以交叉连接需要时间。(我可能错了,但你的解决方案是一种带有附加条件的交叉连接。如果我错了,请随时纠正我。)我同意这一点,但是否有可能只获得一次所有位置