입문7분 분량

DynamoDB PartiQL 대 SQL: 무엇이 깨지나

DynamoDB PartiQL을 둘러싼 가장 큰 혼란의 근원은 — 사람이든 AI 어시스턴트든 마찬가지로 — 그것을 관계형 SQL로 여기는 것입니다. 그렇지 않습니다. PartiQL은 DynamoDB의 기존 연산 위에 얹힌 SQL 호환 표면이지, 조인하거나 그룹화하거나 집계할 수 있는 쿼리 엔진이 아닙니다. 익숙한 키워드가 아래의 아주 다른 기계를 감추고 있습니다.

DynamoDB PartiQL은 SQL과 어떻게 다른가요?

PartiQL은 SQL의 문법은 빌려오지만 그 엔진은 빌려오지 않습니다. DynamoDB에서 모든 문은 단일 네이티브 연산 — GetItem, Query, Scan, PutItem, UpdateItem, DeleteItem — 으로 매핑되므로 JOIN, GROUP BY, 서브쿼리, 집계가 없습니다. SQL처럼 읽히지만 그 키-값 연산들이 이미 할 수 있는 것만 할 수 있습니다.

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

여러분이 쓰는 것DynamoDB가 실행하는 것
SELECT … WHERE PK = …GetItem 또는 Query
SELECT … (PK 없음)Scan (테이블 전체를 읽음)
INSERT INTO …PutItem
UPDATE … WHERE PK=… AND SK=…UpdateItem (항목 하나)
DELETE … WHERE PK=… AND SK=…DeleteItem (항목 하나)

두 테이블에서 읽거나, 해시 조인을 만들거나, 행을 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이 조인·그룹화·집계를 못 하는 이유입니다.

무엇이 다른가 — 기능별로

Workbench 열이 PartiQL의 아니요에 맞서 라고 말하는 곳마다, 그것이 DynoTable의 SQL 가 메우는 격차입니다. Workbench는 여러분의 테이블을 DynamoDB의 실제 쿼리 런타임을 통해 구체화하고 그 위에서 진짜 SQL을 실행합니다 — DynamoDB의 액세스 패턴 규칙 안에서의 SQL.

기능표준 SQLDynamoDB PartiQLDynoTable Workbench
JOIN … ON …아니요예 — INNER / LEFT (PK 또는 GSI 파티션 키 대상)
RIGHT / FULL / CROSS / 콤마 조인아니요아니요
셀프 조인아니요아니요 (아직)
서브쿼리 / 파생 테이블아니요아니요
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예 (없는 속성은 NULL이 아니라 MISSINGIS MISSING 사용)
PK 없는 SELECT *스캔함부분적 — 조용한 테이블 전체 Scan예 (비용 가시성 포함)

무엇이 깨지고, 왜

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

  • 없는 SELECT *는 숨은 Scan입니다. PartiQL은 오류를 내지 않습니다. 그저 모든 항목을 읽고 나중에 필터링하는데, 이것이 친근한 문법 뒤에 숨은 고전적인 Query 대 Scan 비용 함정입니다.
  • UPDATE / DELETE는 전체 기본 키가 필요합니다. 이들은 단일 항목 UpdateItem/DeleteItem으로 매핑되므로, WHERE가 파티션 키(그리고 테이블에서는 정렬 키)를 고정해야 합니다. "status = 'open'인 모든 행 업데이트"를 한 문으로 할 수 없습니다.
  • 큰따옴표는 문자열이 아니라 식별자입니다. DynamoDB PartiQL은 여기서 SQL 표준을 따릅니다. "name"은 열/테이블 이름이고, 'name'은 문자열 값입니다. 값을 큰따옴표로 감싸는 것이 가장 흔한 초보자 실수입니다 — 검증기의 메시지는 문자 그대로 "큰따옴표는 DynamoDB PartiQL에서 문자열이 아니라 식별자를 구분합니다. 문자열 값에는 작은따옴표를 쓰세요." 입니다.
  • 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 런타임을 통해 구체화한 다음, 그 위에서 단일 SELECT(집계, 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 / 콤마 조인은 없습니다.
  • 아직 셀프 조인 없음, 서브쿼리 없음, 파생 테이블 없음, 윈도우 함수 없음.
  • 조인과 프로젝션은 스칼라 속성에 대해 작동합니다.

원시 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 탭을 여세요.

업데이트됨