我正在运行一个查询,需要排除所有以前看过的项目并返回一定数量的项目(在这种情况下为10)。项目列表以querystring参数发送,uuid4字符串由'&'分隔。
对于可能非常大的数据库,我认为将exclude语句与查询一起添加是没有意义的,因为大多数结果都不会出现在alreadySeenItems列表中,并且数据库非常大。
以下哪种方法会更快,假设在某些情况下,yetSeenList可能非常大> 1000项。
注意:我通常会使用第一个,但由于我需要完全匹配并且我知道每个单词的起始位置,否则可能有意义
def getItems(request, alreadySeenItems):
newItems = []
allPossibleItems = Items.objects.raw('SELECT "id" FROM items_table WHERE conditions;')
# method 1
for item in allPossibleItems:
if item.id not in alreadySeenItems:
newItems.append(item.id)
if len(newItems) > 10:
return newItems
# method 2
alreadySeenItemsList = alreadySeenItems.split('&')
for item.id in allPossibleItems:
if not checkForItemInList(item.id, alreadySeenItems)
newItems.append(item.id)
if len(newItems) > 10:
return newItems
# method 3
alreadySeenItemsSet = set(alreadySeenItems.split('&'))
for item.id in allPossibleItems:
if not item.id in alreadySeenItemsSet
newItems.append(item.id)
if len(newItems) > 10:
return newItems
def checkForItemInList(item, items):
for tmp in items:
if item == tmp:
return True
return False
答案 0 :(得分:1)
如果您使用Python内置的set
数据结构,那么无论您做什么都会快得多。如果你有一些可用的内存,那么检查包含是非常快的,但是1k项目什么都不是。见https://docs.python.org/2/library/stdtypes.html#set
不要回避原始问题,但我们也无法确定您的数据库是否真的很大。你有没有为你的表添加索引?只要大多数结果具有某种性质或导致某些低效率,一些系统(至少Postgresql)允许“部分索引”,这允许您仅在某些值上构建索引,这可以使事情变得更加精简 - 但我不确定这是否与你相关。
无论如何,这是一个例子:
import random
num_elements = 10000
def checkForItemInList(item, items):
for tmp in items:
if item == tmp:
return True
return False
def run_experiment(values, use_set):
for i in range(num_elements):
# We know this will be in there...
random_elem = random.randint(0, num_elements - 1)
if use_set:
random_elem in values
else:
checkForItemInList(random_elem, values)
values = range(num_elements)
values_as_set = set(values)
#run_experiment(values_as_set, True)
run_experiment(values, False)
使用set = True版本(注释掉)平均给我约0.05秒,而非设置版本约为2.5秒。