TIL: Postgres 쿼리, 시간 스탬프가 작거나 같음을 주의하십시오.

사진작가Jonas JacobssonUnsplash
그래서 일주일 전에 저는 UUID와 타임 스탬프의 조합으로 Postgres에서 페이지 나누기와 관련된 실험을 했습니다.나는 같은 시간 스탬프에서 내가 만든 시간 스탬프를 조회할 때 재미있는 문제를 만났다.

컨텍스트


상하문을 제공하기 위해서 나는 이런 데이터베이스 모델을 가지고 있다.

궁금해서 제 응용 프로그램에 부하 테스트를 하고 있습니다. 많은 병렬 사용자가 있고 100개의 병렬 삽입이 있습니다.이로 인해 내 데이터베이스에 많은 줄이 같은 시간 스탬프를 가지고 있다.예를 들어, 아래에서





보시다시피 모든 기록의 생성 시간은 동일합니다(최대 100개의 기록이 있을 수 있습니다)


Problems


그래서 내가 만든 시간에 따라 조회를 할 때 이상한 행동이 있다. 나는 이것이 버그나 뭐라고 생각한다



SELECT \* FROM payment\_with\_uuid 
WHERE 
created\_time **<= '2020-05-24 21:27:10'**
ORDER BY created\_time DESC LIMIT 10;

따라서, 이 검색에서 내가 실현하고자 하는 것은, 창설 시간이 주어진 시간 스탬프 (<=) 보다 작거나 같은 모든 기록을 선택하는 것이다


하지만 내가 얻은 것은 모든 시간 스탬프일 뿐, 필터링된 시간 스탬프보다 작다.동일한 값이 있는 타임 스탬프를 필터링하지 않음


아래 예시줄에서





내가 얻은 결과는 케인뿐이지만, Allistair와 James는 여과되지 않았다


또 다른 이상한 것은, 만약 내가 검색을 반전시킨다면, 예를 들면, (>=) 문법보다 큰 문법을 사용한다면, 나는 다른 사람, 예를 들면 Allistair와 James를 얻을 수 있지만, 케인은 분명히 실수를 할 것이다


Solutions and Things that I just Learned


The timestamp is an integer UNIX-timestamp under the hood


그래서 전체 인터넷에서 검색한 후에 분명히 제 친구에게 물어봤는데 저는 답을 얻었습니다. 기본적으로 데이터베이스에 저장된 시간 스탬프는 숨겨진 유닉스 시간 스탬프입니다


예를 들어, 위의 예에서 데이터베이스 레코드를 보았을 때 저장된 시간 스탬프는 다음과 같습니다



**2020-05-24 21:27:10**

실제로 이것은 진정한 값이 아닙니다. 왜냐하면 Postgres는 이 줄의 UNIX 타임 스탬프 버전을 실제로 저장했기 때문입니다.그것은 나노초 또는 마이크로초가 있을 수 있기 때문에 초 버전에서 멈출 뿐만 아니라


이렇게 보일 수도 있어,



**2020-05-24 21:27:10.37091**

우리는 모른다.포맷을 위해 Postgre는 두 번째 값에만 반올림하기 때문입니다


그래서 나는 나의 조회를 더욱 구체적인 것으로 바꾸었다. 나초나 미초를 포함해서 보기에 이렇다. 이것은 가능하다



SELECT \* FROM payment\_with\_uuid 
WHERE 
created\_time **<= '2020-05-24 21:27:10.37091****'**
ORDER BY created\_time DESC LIMIT 10;

하지만, 응용 프로그램 단계에서 어떻게 이 점을 할 수 있는지에 대한 문제가 하나 더 있습니다.하지만 저에게는 Golang을 사용하기 때문에 쉬워요


Using RFC3339Nano On Golang


내 응용 프로그램은 Golang 위에 세워졌기 때문에 정밀도를 포함한 문제를 처리하기 위해 시간을 사용했다.Golang time package의 RFC3339Nano그 형식은 다음과 같습니다. "2006 – 01 – 02T15:04:05.9999999 Z07:00".또는 상세 정보here


Golang 패키지의 시간 형식


나는 어떻게 다른 프로그래밍 언어에서 이 점을 하는지 모르겠지만, 관건은 시간 스탬프 조회의 정밀도를 포함하는 것이다


따라서 최종 사용자로부터 타임스탬프를 받는 조회를 실행할 때, 우리는 먼저 RFC3339Nano를 사용하여 이를 포맷하여 데이터베이스로 보내야 한다.따라서, 조회는 여전히 유효합니다


하지만, 만약 내가 형식을 사용하지 않을 수 있다면, 왜 나는 형식을 사용해야 합니까?만약 우리가 그것을 포맷하지 않는다면, 시간 데이터 구조도 밀리초와 나초를 포함할 것이다.그래서 배경을 제시하자면, 왜 내가 이걸 필요로 하는지, 특히 내 상황에서


따라서 페이지를 나누는 데 사용되는created_시간을 커서로 다음 페이지를 가져옵니다. 이 시간 스탬프를 가져와 문자열로 변환합니다.사용자가 이 문자열을 커서로 사용하여 새 페이지를 가져옵니다


내 프로그램에서 이 문자열을 타임 스탬프로 바꾸어 조회에 사용합니다.따라서 우리는 신중하게 행동해야 한다.Golang에서 시간 스탬프를 문자열로 변환할 때, Postgres에서 얻은 정밀도를 포함하지 않을 수 있기 때문이다.이것이 바로 내가 시간에 따라 격식을 조정해야 하는 이유다.RFC3339Nano





따라서, 문자열로 변환하여 시간 스탬프로 되돌려도 정밀도를 유지합니다


References



  1. Postgres: using timestamps for pagination  — Stackoverflow(설명 스레드에서)
    https://medium.com/media/1f83e4a733ad3206f47e6dd38aa4fc6d/href
    * * *

좋은 웹페이지 즐겨찾기