Spanner에서 읽기 전용 트랜잭션 또는 단일 읽기 호출로 데이터를 읽을 때 타임스탬프 경계를 설정하여 Spanner에서 데이터를 읽을 타임스탬프를 선택하는 방식을 지정합니다.
타임스탬프 경계를 설정하는 이유는 무엇일까요? 데이터베이스가 지리적으로 분산되어 있고(즉, 멀티 리전 인스턴스 구성을 사용하여 Spanner 인스턴스를 만든 경우) 애플리케이션에서 데이터를 읽을 때 일부 비활성을 허용한다면 강력 읽기 대신 비활성 읽기를 실행하여 지연 시간상의 이점을 얻을 수 있습니다. (읽기에서 이러한 읽기 유형에 대해 자세히 알아보세요.)
타임스탬프 경계 유형
타임스탬프 경계 유형은 다음과 같습니다.
강력(기본값): 최신 데이터를 읽습니다.
제한된 비활성: 경계 이후의 데이터 버전을 읽습니다.
완전 비활성: 정확한 타임스탬프의 데이터 버전을 읽습니다. 과거의 특정 시점을 나타내지만 아직 지나지 않은 시간의 타임스탬프를 지정할 수도 있습니다. 미래의 타임스탬프를 지정하면 Spanner는 해당 타임스탬프가 될 때까지 기다렸다가 읽기를 처리합니다.
참고:
이러한 타임스탬프 경계 모드를 사용하는 읽기는 읽기-쓰기 트랜잭션에 속하지 않지만 동시 읽기-쓰기 트랜잭션의 커밋 대기를 차단할 수 있습니다. 제한된 비활성 읽기는 차단을 방지하기 위해 타임스탬프를 선택하려고 시도하지만 그래도 차단될 수 있습니다.
비활성 읽기(즉, 제한된 비활성 또는 완전 비활성 유형을 사용하는 읽기)는 비활성 간격이 길수록 성능이 좋습니다. 성능상의 이점을 얻으려면 비활성을 10초 이상 사용합니다.
Spanner는 이전 버전의 데이터를 읽을 수 있는 가장 이른 시간을 지정하는 데이터베이스의 earliest_version_time를 추적합니다. 가장 초기 버전 시간 이전의 타임스탬프에서는 읽을 수 없습니다.
Spanner 타임스탬프 경계 유형은 아래에 자세히 설명되어 있습니다.
Strong
Spanner는 강력 읽기를 위한 경계 유형을 제공합니다. 강력 읽기에서는 읽기를 시작하기 전에 커밋한 모든 트랜잭션의 영향을 확인할 수 있습니다. 또한 단일 읽기 결과로 가져오는 모든 행은 서로 일관됩니다. 읽기의 일부에서 트랜잭션을 관찰하면 읽기의 모든 부분에서 트랜잭션을 확인합니다.
강력 읽기는 반복할 수 없습니다. 동시 쓰기가 있을 경우 연속된 두 번의 강력 읽기 전용 트랜잭션은 일관되지 않은 결과를 반환할 수 있습니다. 읽기 간 일관성이 필요하면 같은 트랜잭션 또는 정확한 읽기 타임스탬프에서 읽기를 실행해야 합니다.
제한된 비활성
Spanner는 제한된 비활성을 위한 경계 유형을 제공합니다. 제한된 비활성 모드를 사용하면 사용자가 제공한 비활성 경계에 따라 Spanner에서 읽기 타임스탬프를 선택할 수 있습니다. Spanner는 비활성 경계 내에서 최신 타임스탬프를 선택하여 차단하지 않고 사용할 수 있는 가장 가까운 복제본의 읽기를 실행할 수 있습니다.
가져온 모든 행은 서로 일관됩니다. 읽기의 일부에서 트랜잭션을 관찰하면 읽기의 모든 부분에서 트랜잭션을 확인합니다. 제한된 비활성 읽기는 반복할 수 없습니다. 두 번의 비활성 읽기는 같은 비활성 경계를 사용하더라도 다른 타임스탬프를 실행할 수 있으므로 일관되지 않은 결과를 반환합니다.
제한된 비활성 읽기는 대등한 완전 비활성 읽기보다 일반적으로 약간 느립니다.
완전 비활성
Spanner는 완전 비활성을 위한 경계 유형을 제공합니다. 이러한 타임스탬프 경계는 사용자가 지정한 타임스탬프에서 읽기를 실행합니다. 타임스탬프의 읽기에서는 전체 트랜잭션 내역의 일관된 프리픽스를 확인할 수 있습니다. 이러한 읽기는 읽기 타임스탬프보다 적거나 같은 커밋 타임스탬프의 모든 트랜잭션으로 수행한 수정 사항을 관찰하고 큰 커밋 타임스탬프의 트랜잭션에서 수행한 수정 사항은 관찰하지 않습니다. 또한 읽기 타임스탬프보다 적거나 같은 커밋 타임스탬프를 할당할 수 있는 모든 충돌 트랜잭션이 완료될 때까지 차단합니다.
이 타임스탬프는 완전 Spanner 커밋 타임스탬프 또는 현재 시간에 비교해 비활성으로 표현할 수 있습니다.
이러한 모드에서는 타임스탬프를 선택하는 '협상 단계'가 필요하지 않습니다. 따라서 제한된 방식을 사용하는 동등한 비활성 동시 실행 모드보다 약간 빠르게 실행됩니다. 반면에 제한된 비활성 읽기는 대개 좀 더 최신 결과를 반환합니다.
최대 타임스탬프 비활성
Spanner는 지속적으로 백그라운드에서 삭제되거나 덮어쓴 데이터를 가비지 컬렉션하여 저장공간을 확보합니다. 이 프로세스를 버전 GC라고 합니다. 버전 GC는 데이터베이스의 version_retention_period을 지나 만료되면 버전이 복원되며, 기본값은 1시간이지만 최대 1주까지 구성할 수 있습니다.
이 제한은 실행하는 중에 타임스탬프가 너무 오래되어 버리는 진행 중인 읽기 또는 SQL 쿼리에도 적용됩니다. 읽기 타임 스탬프가 너무 오래된 읽기 및 SQL 쿼리는 실패하고 FAILED_PRECONDITION 오류가 표시됩니다. 단, 파티션 토큰이 포함된 파티션 읽기/쿼리는 세션이 활성 상태를 유지하는 동안 만료된 데이터의 가비지 컬렉션을 방지합니다.
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["이해하기 어려움","hardToUnderstand","thumb-down"],["잘못된 정보 또는 샘플 코드","incorrectInformationOrSampleCode","thumb-down"],["필요한 정보/샘플이 없음","missingTheInformationSamplesINeed","thumb-down"],["번역 문제","translationIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-09-05(UTC)"],[],[],null,["# Timestamp bounds\n\nIntroduction\n------------\n\nWhen reading data in Spanner in either a\n[read-only transaction](/spanner/docs/transactions#read-only_transactions) or a\n[single read call](/spanner/docs/reads), you can set a **timestamp bound**, which\ntells Spanner how to choose a timestamp at which to read the data.\n\nWhy set a timestamp bound? If your database is geographically distributed (that\nis, you created your Spanner instance using a multi-region instance\nconfiguration), and your application can tolerate some staleness when reading\ndata, then you can get latency benefits from executing a stale read instead of a\nstrong read. (Learn more about these read types in [Reads](/spanner/docs/reads).)\n\nTimestamp bound types\n---------------------\n\nThe types of timestamp bound are:\n\n- Strong (the default): read the latest data.\n- Bounded staleness: read a version of the data that's no staler than a bound.\n- Exact staleness: read the version of the data at an exact timestamp, e.g. a point in time in the past, though you can specify a timestamp for a time that hasn't passed yet. (If you specify a timestamp in the future, Spanner will wait for that timestamp before serving the read.)\n\nNotes:\n\n- Although reads using these timestamp bound modes are not part of a read-write\n transaction, they can block waiting for concurrent read-write transactions to\n commit. Bounded staleness reads attempt to pick a timestamp to avoid blocking,\n but may still block.\n\n- Stale reads (i.e. using the bounded or exact staleness types) have the maximum\n performance benefit at longest staleness intervals. Use a minimum staleness of\n 10 seconds to get a benefit.\n\n- Spanner keeps track of a database's [`earliest_version_time`](/spanner/docs/reference/rest/v1/projects.instances.databases#Database.FIELDS.earliest_version_time), which specifies the earliest time at which past versions of data can be read. You cannot read at a timestamp before the earliest version time.\n\nThe Spanner timestamp bound types are explained in more detail below.\n\n### Strong\n\nSpanner provides a bound type for strong reads. Strong reads are\nguaranteed to see the effects of all transactions that have committed before the\nstart of the read. Furthermore, all rows yielded by a single read are consistent\nwith each other - if any part of the read observes a transaction, all parts of\nthe read see the transaction.\n\nStrong reads are not repeatable: two consecutive strong read-only transactions\nmight return inconsistent results if there are concurrent writes. If consistency\nacross reads is required, the reads should be executed within the same\ntransaction or at an exact read timestamp.\n\n### Bounded staleness\n\nSpanner provides a bound type for bounded staleness. Bounded staleness\nmodes allow Spanner to pick the read timestamp, subject to a user-\nprovided staleness bound. Spanner chooses the newest timestamp within\nthe staleness bound that allows execution of the reads at the closest available\nreplica without blocking.\n\nAll rows yielded are consistent with each other - if any part of the read\nobserves a transaction, all parts of the read see the transaction. Boundedly\nstale reads are not repeatable: two stale reads, even if they use the\nsame staleness bound, can execute at different timestamps and thus return\ninconsistent results.\n\nBounded staleness reads are usually a little slower than comparable exact\nstaleness reads.\n| **Note:** If you're using bounded staleness with a read-only transaction, you can only use it with single-use read-only transactions, not with general-purpose read-only transactions.\n\n### Exact staleness\n\nSpanner provides a bound type for exact staleness. These timestamp\nbounds execute reads at a user-specified timestamp. Reads at a timestamp are\nguaranteed to see a consistent prefix of the global transaction history: they\nobserve modifications done by all transactions with a commit timestamp less than\nor equal to the read timestamp, and observe none of the modifications done by\ntransactions with a larger commit timestamp. They will block until all\nconflicting transactions that may be assigned commit timestamps less than or\nequal to the read timestamp have finished.\n\nThe timestamp can either be expressed as an absolute Spanner commit\ntimestamp or a staleness relative to the current time.\n\nThese modes do not require a \"negotiation phase\" to pick a timestamp. As a\nresult, they execute slightly faster than the equivalent boundedly stale\nconcurrency modes. On the other hand, boundedly stale reads usually return\nfresher results.\n\nMaximum timestamp staleness\n---------------------------\n\nSpanner continuously garbage collects deleted and overwritten data\nin the background to reclaim storage space. This process is known as **version\nGC** . Version GC reclaims versions after they expire past a database's [`version_retention_period`](/spanner/docs/reference/rest/v1/projects.instances.databases#Database.FIELDS.version_retention_period), which defaults to 1 hour, but can be configured up to 1 week.\nThis restriction also applies to in-progress reads and/or SQL queries\nwhose timestamp become too old while executing. Reads and SQL queries with\ntoo-old read timestamps fail with the error `FAILED_PRECONDITION`. The only\nexception is [Partition Read/Query](/spanner/docs/reads#read_data_in_parallel) with\npartition tokens, which will prevent garbage collection of expired data while\nthe session remains active."]]