Я написал функцию для сохранения счетчиков, о которых я упоминал, в конце оригинального сообщения, так что вот один из возможных ответов для удаления поиска по дублирующему индексу.Я все еще хотел бы знать, выполнимо ли это с прямым SQL.
Я создал сквозную пользовательскую функцию для захвата счетчика из подзапроса при вычислении смещения.
Так что вместо оригиналаquery:
SELECT id, prev_node, next_node FROM edges WHERE prev_node = ? LIMIT 1
OFFSET abs(random())%(
SELECT count(*) FROM edges WHERE prev_node = ?);
У меня есть что-то вроде этого:
SELECT id, prev_node, next_node FROM edges WHERE next_node = ? LIMIT 1
OFFSET abs(random())%(
cache(?, (SELECT count(*) FROM edges WHERE prev_node = ?));
Первый аргумент для cache () - это уникальный идентификатор для этого количества.Я мог бы просто использовать значение prev_node, но из-за приложения мне нужно иметь возможность кэшировать счетчики для прямого и обратного обхода по отдельности.Поэтому я использую «$ direction: $ prev_node_id» в качестве ключа.
Функция кэширования выглядит следующим образом (с использованием Python):
_cache = {}
def _cache_count(self, key, count):
self._cache[key] = count
return count
conn.create_function("cache", 2, self._cache_count)
А затем в функции случайного блуждания,Я могу использовать хеш-ключ и проверить, известен ли счет.Если это так, я использую вариант основного запроса, который не включает подзапрос:
uncached = "SELECT id, next_node, prev_node " \
"FROM edges WHERE prev_node = :last LIMIT 1 " \
"OFFSET abs(random())%cache(:key, " \
" (SELECT count(*) FROM edges WHERE prev_node = :last))"
cached = "SELECT id, next_node, prev_node, has_space, count " \
"FROM edges WHERE prev_node = :last LIMIT 1 " \
"OFFSET abs(random())%:count"
key = "%s:%s" % (direction, last_node)
if key in cache:
count = cache[key]
query = cached
args = dict(last=last_node, count=count)
else:
query = uncached
args = dict(last=last_node, key=key)
row = c.execute(query, args).fetchone()
Кэшированные запросы выполняются примерно в два раза быстрее, чем некэшированные в среднем (5,7 и 10,9)..