입문6분 분량

DynamoDB PartiQL vs SQL: 무엇이 다르고 (무엇이 깨지는가)

DynamoDB PartiQL에 대한 가장 큰 혼란의 원인은 — 사람이든 AI 어시스턴트든 — 그것을 관계형 SQL로 취급하는 것입니다. PartiQL은 SQL이 아닙니다. PartiQL은 DynamoDB의 기존 연산 위에 얹힌 SQL 호환 표면일 뿐, 조인하거나 그룹화하거나 집계할 수 있는 쿼리 엔진이 아닙니다. 익숙한 키워드 뒤에는 전혀 다른 기계가 숨어 있습니다.

멘탈 모델

모든 PartiQL 문은 DynamoDB의 네이티브 연산 중 하나로 컴파일됩니다:

작성하는 것DynamoDB가 실행하는 것
SELECT … WHERE PK = …GetItem or Query
SELECT … (no PK)Scan (reads the whole table)
INSERT INTO …PutItem
UPDATE … WHERE PK=… AND SK=…UpdateItem (one item)
DELETE … WHERE PK=… AND SK=…DeleteItem (one item)

두 테이블에서 읽거나, 해시 조인을 만들거나, 행을 COUNT로 접을 수 있는 플래너는 없습니다. 어떤 연산이 단일 Get/Query/Scan/Put/Update/Delete로 매핑되지 않으면, PartiQL은 그것을 표현할 수 없습니다. 그것이 전부입니다 — 아래의 모든 내용은 이 하나의 사실에서 비롯된 결과입니다.

같은 매핑을 흐름으로 본 것 — WHERE 절이 SELECT을 저렴한 Query로 만들지 전체 테이블 Scan으로 만들지를 결정합니다:

WHERE pins full PKno PK in WHEREPartiQL statementSELECT?Query (one partition)Scan (whole table)INSERT PutItemUPDATE UpdateItemDELETE DeleteItem

각 문은 정확히 하나의 네이티브 연산으로 귀결됩니다 — 그 일대일 매핑이 바로 PartiQL이 조인하거나 그룹화하거나 집계할 수 없는 이유입니다.

무엇이 다른가 — 기능별로

DynoTable의 SQL Workbench가 실행할 수 있는 항목에는 표시를 해두었습니다. Workbench는 DynamoDB의 실제 쿼리 런타임을 통해 테이블을 구체화한 다음 그 위에서 실제 SQL을 실행합니다 — DynamoDB의 액세스 패턴 규칙 안에서의 SQL.

기능표준 SQLDynamoDB PartiQLDynoTable Workbench
JOIN … ON … INNER / LEFT (to a PK or GSI partition key)
RIGHT / FULL / CROSS / comma-join
셀프 조인 (아직)
서브쿼리 / 파생 테이블
CTE (WITH …)
UNION / INTERSECT / EXCEPT
GROUP BY / HAVING
집계 (COUNT/SUM/AVG/MIN/MAX)
DISTINCT
CASE / CAST
윈도 함수
ORDER BY 임의의 열 정렬 키만 (파티션 키 WHERE 필요) 임의의 열
LIMIT 인라인 (요청 limit 파라미터 사용)
LIKE (contains / begins_with 사용)
IS NULL / IS NOT NULL (attribute_not_exists / attribute_exists 사용)
SELECT * without a PK스캔 조용한 전체 테이블 Scan (비용 가시성 포함)

무엇이 깨지고, 왜 그런가

다음은 쿼리가 와이어에 도달하기 전에 DynoTable의 PartiQL 검증기가 표시하는 실패들입니다 — 각각은 실제 DynamoDB 제약으로 거슬러 올라갑니다.

  • 파티션 키 없는 SELECT *는 숨겨진 Scan입니다. PartiQL은 오류를 내지 않습니다. 그냥 모든 항목을 읽은 다음 사후에 필터링하는데, 이것은 친근한 구문 뒤에 숨은 전형적인 Query-vs-Scan 비용 함정입니다.
  • UPDATE / DELETE는 전체 기본 키가 필요합니다. 이들은 단일 항목 UpdateItem/DeleteItem으로 매핑되므로, WHERE가 파티션 키를(그리고 복합 키 테이블에서는 정렬 키도) 지정해야 합니다. "status = 'open'인 모든 행을 업데이트"하는 것을 한 문장으로 할 수는 없습니다.
  • 큰따옴표는 문자열이 아니라 식별자입니다. DynamoDB PartiQL은 여기서 SQL 표준을 따릅니다: "name"은 열/테이블 이름이고, 'name'은 문자열 값입니다. 큰따옴표로 값을 감싸는 것은 가장 흔한 초보자 실수입니다 — 검증기의 메시지는 말 그대로 "Double quotes delimit identifiers in DynamoDB PartiQL, not strings. Use single quotes for string values." 입니다.
  • IN은 괄호가 아니라 대괄호를 사용합니다: WHERE pk IN ['a','b'], PK 값은 최대 50개 / 비키 값은 100개로 제한됩니다.
  • JOIN도 집계도 없습니다. 테이블을 결합하거나 행을 접을 엔진이 없습니다. 이것이 단일 테이블 설계의 트레이드오프입니다: 쿼리 계층이 사후에 데이터를 재구성할 수 없기 때문에 액세스 패턴을 미리 모델링해야 합니다.

AI 어시스턴트가 이것을 틀리는 이유

LLM은 방대한 관계형 SQL로 학습되었기 때문에, DynamoDB에 대해 JOIN, GROUP BY, LIKE, 인라인 LIMIT, 큰따옴표 문자열 리터럴을 자신 있게 내놓습니다 — 이 모두를 DynamoDB는 거부합니다. DynoTable 자체의 모델 쿼리 자동 수정이 존재하는 것은 바로 저렴한 모델이 이런 패턴을 안정적으로 만들어내기 때문입니다: 이중 이스케이프된 따옴표를 제거하고, LIKE '%x%'contains, IS NULLattribute_not_exists로 다시 쓰며, 인라인 LIMIT을 요청 파라미터로 끌어올립니다. AI가 Postgres처럼 읽히는 "PartiQL"을 생성하고 있다면, 그것이 바로 신호입니다.

각 카드는 관계형 개발자가 찾는 SQL, DynamoDB PartiQL이 그것으로 실제로 하는 일, 그리고 그 이유를 보여줍니다. “DynoTable에서 실행됨”으로 표시된 카드는 워크벤치가 실행할 수 있는 동등한 SQL을 보여줍니다.
Joining two tables
PartiQL에 없음
SELECT o.id, c.name
FROM orders o
JOIN customers c ON o.customerId = c.PK
GROUP BY and aggregates
PartiQL에 없음
SELECT country, COUNT(*) AS orders, SUM(total) AS revenue
FROM orders
GROUP BY country
Subqueries
PartiQL에 없음
SELECT * FROM orders
WHERE customerId IN (SELECT PK FROM customers WHERE country = 'ES')
UNION across tables
PartiQL에 없음
SELECT PK FROM orders
UNION
SELECT PK FROM archived_orders
SELECT * (the hidden Scan)
동작하지만 제약 있음
SELECT * FROM orders
Updating many rows by a filter
PartiQL에 없음
UPDATE orders SET status = 'shipped'
WHERE status = 'open'
Quoting string values
동작하지만 제약 있음
SELECT * FROM users WHERE "name" = "Alice"

DynoTable의 SQL Workbench: PartiQL로 실행할 수 없는 쿼리

JOIN이나 GROUP BY가 정말로 필요할 때, DynoTable의 SQL Workbench가 답입니다. 각 JOIN의 대상 측을 파티션 키에 대해 검증하고, 조인된 행을 DynamoDB의 실제 Query/Scan 런타임을 통해 구체화한 다음, 그 위에서 전체 SQL(집계, GROUP BY, DISTINCT, CASE, CAST)을 실행합니다 — DynamoDB의 액세스 패턴 규칙 안에서의 SQL.

-- Runs in the DynoTable Workbench (NOT in PartiQL):
SELECT c.country, COUNT(*) AS orders, SUM(o.total) AS revenue
FROM orders o
INNER JOIN customers c ON o.customerId = c.PK
GROUP BY c.country
ORDER BY revenue DESC

정직한 제약(Workbench는 DynamoDB의 액세스 모델을 강제하며, Postgres인 척하지 않습니다):

  • INNER JOINLEFT JOIN만 — ON의 대상 속성은 파티션 키 또는 GSI 파티션 키여야 합니다. RIGHT / FULL / CROSS / comma-join은 없습니다.
  • 아직 셀프 조인, 서브쿼리, 파생 테이블, 윈도 함수는 없습니다.
  • 조인과 프로젝션은 스칼라 속성에 대해 작동합니다.

조건과 키 표현식만 원시 API용으로 구성하면 된다면, DynamoDB Expression Builder가 PartiQL 표면을 전혀 거치지 않고 올바른 FilterExpression / KeyConditionExpression을 생성합니다. PartiQL을 제대로 쓰는 법은 작업된 PartiQL 예제를 참고하세요. 어떤 쿼리든 비용이 얼마나 들지 가늠하려면 항목 크기 계산기를 사용하세요. PartiQL은 와이어 형식을 절대 바꾸지 않는다는 점에 유의하세요 — 값은 여전히 DynamoDB-JSON으로 전송됩니다. 클라이언트를 고르고 계신가요? Workbench가 평범한 DynamoDB GUIDynobase와 비교해 어디에 위치하는지 확인해 보세요.

FAQ

PartiQL은 SQL과 같은가요? 아닙니다. PartiQL은 SQL 호환 쿼리 언어이지만, DynamoDB에서는 단일 Get/Query/Scan/Put/Update/Delete로 매핑되는 연산만 노출합니다. 조인, 집계, 서브쿼리, GROUP BY가 없습니다.

DynamoDB PartiQL로 JOIN을 할 수 있나요? 아닙니다. DynamoDB PartiQL은 테이블을 조인할 수 없습니다. DynoTable의 SQL Workbench는 DynamoDB의 실제 쿼리 런타임을 통해 데이터를 구체화하여 INNER/LEFT JOIN(파티션 키 또는 GSI 파티션 키 대상)을 실행할 수 있습니다.

DynamoDB PartiQL은 GROUP BY나 COUNT를 지원하나요? 아닙니다 — DynamoDB PartiQL에는 집계나 GROUP BY가 없습니다. COUNT/SUM/AVG/GROUP BY/HAVING 쿼리에는 DynoTable의 SQL Workbench를 사용하세요.

SELECT *는 왜 이렇게 비싼가요? WHERE에 파티션 키가 없으면, PartiQL은 전체 테이블 Scan을 실행하고 필터가 적용되기 전에 모든 항목 읽기를 계량합니다. 파티션 키 술어를 추가하여 Query로 바꾸세요.

PartiQL에서 작은따옴표를 써야 하나요, 큰따옴표를 써야 하나요? 문자열 값에는 작은따옴표('CUSTOMER#42'), 테이블·속성 이름 같은 식별자에는 큰따옴표("AppData")를 씁니다. 값을 큰따옴표로 감싸는 것은 가장 흔한 PartiQL 실수입니다.

DynamoDB에 대해 실제 SQL을 실행할 준비가 되셨나요? DynoTable 다운로드 후 Workbench 탭을 열어 보세요.

업데이트됨