2011-09-25 6 views
3

내가 임의의 오프셋 값을 결정하기 위해 하위 쿼리를 사용하여 SQLite는의 테이블에서 임의의 행을 선택하고있어에서 오프셋 하위 쿼리 결과를 반환 : 그것을이 내 작업에 대한 기능적으로 올바른sqlite3를

SELECT id, prev_node, next_node FROM edges WHERE prev_node = ? LIMIT 1 
    OFFSET abs(random())%(SELECT count(*) FROM edges WHERE prev_node = ?); 

,하지만를 인덱스에 두 개의 안타가 필요합니다

0|0|TABLE edges WITH INDEX edges_all_prev 
0|0|TABLE edges WITH INDEX edges_all_prev 

쿼리는 가장자리의 수가 증가대로의 결과를 캐시하는 데 도움이 될 것입니다, 그래서 한 번 이상 동일한 노드를 방문 할 가능성이 높다 랜덤 워크입니다 SELECT count(*) 하위 쿼리

다른 하위 반환 값과 함께 하위 쿼리의 값을 선택할 수 있습니까?

쿼리에 대한 VDBE 덤프를 보면 해당 값이 도달 범위를 벗어납니다. 이 레지스터의 결과 행 레지스터 16-18 (단계 42)에서 생성되는 동안 (스텝 (21)이 이동) 8 : 그것은 이후에 I가 카운트를 저장하는 기능을 만들 수

0|Trace|0|0|0||00| 
1|Integer|1|1|0||00| 
2|Function|0|0|5|random(0)|00| 
3|Function|0|5|4|abs(1)|01| 
4|If|7|23|0||00| 
5|Integer|1|7|0||00| 
6|Null|0|8|0||00| 
7|Integer|1|9|0||00| 
8|Null|0|10|0||00| 
9|Variable|2|11|1||00| 
10|Goto|0|47|0||00| 
11|OpenRead|2|15|0|keyinfo(4,BINARY,BINARY)|00| 
12|IsNull|11|18|0||00| 
13|Affinity|11|1|0|d|00| 
14|SeekGe|2|18|11|1|00| 
15|IdxGE|2|18|11|1|01| 
16|AggStep|0|0|10|count(0)|00| 
17|Next|2|15|0||00| 
18|Close|2|0|0||00| 
19|AggFinal|10|0|0|count(0)|00| 
20|SCopy|10|13|0||00| 
21|Move|13|8|1||00| 
22|IfZero|9|23|-1||00| 
23|Remainder|8|4|2||00| 
24|MustBeInt|2|0|0||00| 
25|IfPos|2|27|0||00| 
26|Integer|0|2|0||00| 
33|Affinity|14|1|0|d|00| 
34|SeekGe|3|45|14|1|00| 
35|IdxGE|3|45|14|1|01| 
36|AddImm|2|-1|0||00| 
37|IfNeg|2|39|0||00| 
38|Goto|0|44|0||00| 
39|IdxRowid|3|16|0||00| 
40|Column|3|0|17||00| 
41|Column|3|1|18||00| 
42|ResultRow|16|3|0||00| 
43|IfZero|1|45|-1||00| 
44|Next|3|35|0||00| 
45|Close|3|0|0||00| 
46|Halt|0|0|0||00| 
47|Transaction|0|0|0||00| 
48|VerifyCookie|0|27|0||00| 
49|TableLock|0|9|0|edges|00| 
50|Goto|0|11|0||00| 

계산되었지만 해당 하위 쿼리의 결과를 요청하기위한 간단한 SQL 구문이 있습니까?

답변

1

나는 원래 게시물 끝에 언급 한 개수를 저장하는 함수를 작성 했으므로 중복 인덱스 검색을 제거 할 수있는 가능한 대답은 여기에 있습니다. 나는 아직도 이것이 곧바로 SQL로 할 수 있는지 알고 싶다.

오프셋을 계산할 때 하위 쿼리에서 카운트를 캡처하는 패스 스루 사용자 함수를 만들었습니다. 그래서 그 대신 원래 쿼리의

는 :

SELECT id, prev_node, next_node FROM edges WHERE next_node = ? LIMIT 1 
    OFFSET abs(random())%(
    cache(?, (SELECT count(*) FROM edges WHERE prev_node = ?)); 

캐시에 대한 첫 번째 인수()는 그 개수에 대한 고유 식별자입니다 :

SELECT id, prev_node, next_node FROM edges WHERE prev_node = ? LIMIT 1 
    OFFSET abs(random())%(
    SELECT count(*) FROM edges WHERE prev_node = ?); 

좀 더 이런 일이있다. I 은 단지 prev_node 값을 사용할 수 있지만 응용 프로그램 덕분에 I 은 앞으로 및 뒤로 이동을 위해 카운트를 캐시 할 수 있어야합니다. . 그래서 "$ 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) 

그리고 다음 랜덤 워크 (random walk) 함수에서, 내가 할 수있는 단점까지 해시 키를 카운트가 이미 알려져 여부를 확인. 이 경우, 나는 부질 포함되지 않습니다 메인 쿼리의 변형 사용

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.7us 대 10.9us)에 .

+1

파이썬 예외 처리의 오버 헤드는 무엇입니까? 캐시되지 않은 경우'cache.has_key (key)'(또는 단지'cache.get (key)'와'None'을 체크하는 것)이 눈에 띄게 빠릅니까? –

+1

좋은 질문입니다! 나는 백만 개의 캐시 히트와 100 만개의 정수 키가있는 사전에 대한 백만 번의 누락으로이를 테스트했습니다. 나는'try/except','has_key','cache '옵션을 시도했습니다.get (key)','cache in key '를 포함한다. 'try/except'는 키가 존재할 때 뛰어난 퍼포먼스를 가지고 있습니다.하지만 그것은 누락 된 것보다 _4x_ 더 나쁩니다. '캐시의 키'는 내가 사용하는 데 평균적인 성능이 가장 좋습니다. –

관련 문제