mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-17 20:41:49 +03:00
f1daabab04
https://github.com/hasura/graphql-engine-mono/pull/2352 Co-authored-by: Rikin Kachhia <54616969+rikinsk@users.noreply.github.com> GitOrigin-RevId: f9f5d1157524afbe418ba0ca3e3e1d6258eaf9e3
187 lines
8.3 KiB
ReStructuredText
187 lines
8.3 KiB
ReStructuredText
.. meta::
|
|
:description: Hasura explain API reference
|
|
:keywords: hasura, docs, explain API, API reference
|
|
|
|
.. _explain_api_reference:
|
|
|
|
Explain API Reference
|
|
=====================
|
|
|
|
.. contents:: Table of contents
|
|
:backlinks: none
|
|
:depth: 2
|
|
:local:
|
|
|
|
Introduction
|
|
------------
|
|
|
|
The Explain API is an admin-only endpoint for analysing queries and subscriptions.
|
|
Given a query and authorization role, it returns backend-specific execution plans.
|
|
|
|
Endpoint
|
|
--------
|
|
|
|
All requests are ``POST`` requests to the ``/v1/graphql/explain`` endpoint.
|
|
|
|
API Spec
|
|
--------
|
|
|
|
Request
|
|
^^^^^^^
|
|
|
|
The request expects a JSON object with the following keys:
|
|
- ``query``: the GraphQL query to be analysed
|
|
- ``user`` (optional): the ``x-hasura-role`` along with session variables
|
|
|
|
.. code-block:: http
|
|
|
|
POST /v1/graphql/explain HTTP/1.1
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"query": "<query>",
|
|
"user": {
|
|
"x-hasura-role" : "...",
|
|
"x-hasura-session-var1" : "..."
|
|
}
|
|
}
|
|
|
|
Sample request
|
|
**************
|
|
|
|
.. code-block:: http
|
|
|
|
POST /v1/graphql/explain HTTP/1.1
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"query": {
|
|
"query": "query getUsers { user { name }}",
|
|
"operationName": "getUsers"
|
|
}
|
|
}
|
|
|
|
|
|
Response
|
|
^^^^^^^^
|
|
|
|
The response for a query is a list of plans, one for each field:
|
|
|
|
.. code-block:: none
|
|
|
|
[
|
|
{
|
|
"field": String -- "name of the field",
|
|
"sql": String -- "generated SQL for the operation",
|
|
"plan": [String] -- "the database's execution plan for the generated SQL"
|
|
}
|
|
]
|
|
|
|
The response for a subscription is a single plan,
|
|
along with the variables used to determine how the subscription will be multiplexed:
|
|
|
|
.. code-block:: none
|
|
|
|
{
|
|
"sql": String -- "generated SQL for the operation",
|
|
"plan": [String] -- "the database's execution plan for the generated SQL"
|
|
"variables": {
|
|
"synthetic": [String], -- "introduced variables for enabling additional query multiplexing (values)"
|
|
"query": Object -- "GraphQL query variables (names and values)"
|
|
"session": Object -- "session variables referenced by the query (names and values)"
|
|
}
|
|
}
|
|
|
|
Sample response for a query
|
|
***************************
|
|
|
|
PostgreSQL backend:
|
|
|
|
.. code-block:: json
|
|
|
|
[
|
|
{
|
|
"field": "user",
|
|
"sql": "SELECT coalesce(json_agg(\"root\" ), '[]' ) AS \"root\" FROM (SELECT row_to_json((SELECT \"_1_e\" FROM (SELECT \"_0_root.base\".\"name\" AS \"name\" ) AS \"_1_e\" ) ) AS \"root\" FROM (SELECT * FROM \"public\".\"user\" WHERE ('true') ) AS \"_0_root.base\" ) AS \"_2_root\" ",
|
|
"plan": [
|
|
"Aggregate (cost=40.00..40.01 rows=1 width=32)",
|
|
" -> Seq Scan on \"user\" (cost=0.00..22.00 rows=1200 width=32)",
|
|
" SubPlan 1",
|
|
" -> Result (cost=0.00..0.01 rows=1 width=32)"
|
|
]
|
|
}
|
|
]
|
|
|
|
Microsoft SQL Server backend:
|
|
|
|
.. code-block:: json
|
|
|
|
[
|
|
{
|
|
"field": "user",
|
|
"sql": "SELECT ISNULL((SELECT [t_user1].[name] AS [name]\nFROM [dbo].[user] AS [t_user1]\nFOR JSON PATH, INCLUDE_NULL_VALUES), '[]')",
|
|
"plan": [
|
|
"SELECT ISNULL((SELECT [t_user1].[name] AS [name]\nFROM [dbo].[user] AS [t_user1]\nFOR JSON PATH, INCLUDE_NULL_VALUES), '[]')",
|
|
" |--Compute Scalar(DEFINE:([Expr1003]=isnull([Expr1001],CONVERT_IMPLICIT(nvarchar(max),'[]',0))))",
|
|
" |--UDX(([t_user1].[name]))",
|
|
" |--Clustered Index Scan(OBJECT:([master].[dbo].[user].[PK__user__3213E83F04195C1B] AS [t_user1]))"
|
|
]
|
|
}
|
|
]
|
|
|
|
Sample response for a subscription
|
|
**********************************
|
|
|
|
PostgreSQL backend:
|
|
|
|
.. code-block:: json
|
|
|
|
{
|
|
"sql": "SELECT \"_subs\".\"result_id\" , \"_fld_resp\".\"root\" AS \"result\" FROM UNNEST(($1)::uuid[], ($2)::json[]) AS \"_subs\"(\"result_id\", \"result_vars\") LEFT OUTER JOIN LATERAL (SELECT json_build_object('user', \"user\".\"root\" ) AS \"root\" FROM (SELECT coalesce(json_agg(\"root\" ), '[]' ) AS \"root\" FROM (SELECT row_to_json((SELECT \"_1_e\" FROM (SELECT \"_0_root.base\".\"name\" AS \"name\" ) AS \"_1_e\" ) ) AS \"root\" FROM (SELECT * FROM \"public\".\"user\" WHERE ('true') ) AS \"_0_root.base\" ) AS \"_2_root\" ) AS \"user\" ) AS \"_fld_resp\" ON ('true') ",
|
|
"plan": [
|
|
"Nested Loop Left Join (cost=40.01..42.28 rows=100 width=48)",
|
|
" -> Function Scan on _subs (cost=0.01..1.00 rows=100 width=16)",
|
|
" -> Materialize (cost=40.00..40.03 rows=1 width=32)",
|
|
" -> Subquery Scan on \"user\" (cost=40.00..40.02 rows=1 width=32)",
|
|
" -> Aggregate (cost=40.00..40.01 rows=1 width=32)",
|
|
" -> Seq Scan on \"user\" user_1 (cost=0.00..22.00 rows=1200 width=32)",
|
|
" SubPlan 1",
|
|
" -> Result (cost=0.00..0.01 rows=1 width=32)"
|
|
],
|
|
"variables": {
|
|
"synthetic": [],
|
|
"query": {},
|
|
"session": {}
|
|
}
|
|
}
|
|
|
|
Microsoft SQL Server backend:
|
|
|
|
.. code-block:: json
|
|
|
|
{
|
|
"sql": "SELECT ISNULL((SELECT [row].[result_id] AS [result_id],\n [result].[json] AS [result]\nFROM OPENJSON((N''+NCHAR(91)+''+NCHAR(91)+''+NCHAR(34)+'00000000-0000-0000-0000-000000000000'+NCHAR(34)+','+NCHAR(123)+''+NCHAR(34)+'synthetic'+NCHAR(34)+''+NCHAR(58)+''+NCHAR(91)+''+NCHAR(93)+','+NCHAR(34)+'query'+NCHAR(34)+''+NCHAR(58)+''+NCHAR(123)+''+NCHAR(125)+','+NCHAR(34)+'session'+NCHAR(34)+''+NCHAR(58)+''+NCHAR(123)+''+NCHAR(125)+''+NCHAR(125)+''+NCHAR(93)+''+NCHAR(93)+''))\n WITH ([result_id] UNIQUEIDENTIFIER '$[0]',\n [result_vars] NVARCHAR(MAX) '$[1]' AS JSON) AS [row]\nOUTER APPLY (SELECT ISNULL((SELECT (SELECT ISNULL((SELECT [t_user1].[name] AS [name]\n FROM [dbo].[user] AS [t_user1]\n FOR JSON PATH, INCLUDE_NULL_VALUES), '[]')) AS [user]\n FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER), '[]')) \nAS [result]([json])\nFOR JSON PATH, INCLUDE_NULL_VALUES), '[]')",
|
|
"plan": [
|
|
"SELECT ISNULL((SELECT [row].[result_id] AS [result_id],\n [result].[json] AS [result]\nFROM OPENJSON((N''+NCHAR(91)+''+NCHAR(91)+''+NCHAR(34)+'00000000-0000-0000-0000-000000000000'+NCHAR(34)+','+NCHAR(123)+''+NCHAR(34)+'synthetic'+NCHAR(34)+''+NCHAR(58)+''+NCHAR(91)+''+NCHAR(93)+','+NCHAR(34)+'query'+NCHAR(34)+''+NCHAR(58)+''+NCHAR(123)+''+NCHAR(125)+','+NCHAR(34)+'session'+NCHAR(34)+''+NCHAR(58)+''+NCHAR(123)+''+NCHAR(125)+''+NCHAR(125)+''+NCHAR(93)+''+NCHAR(93)+''))\n WITH ([result_id] UNIQUEIDENTIFIER '$[0]',\n [result_vars] NVARCHAR(MAX) '$[1]' AS JSON) AS [row]\nOUTER APPLY (SELECT ISNULL((SELECT (SELECT ISNULL((SELECT [t_user1].[name] AS [name]\n FROM [dbo].[user] AS [t_user1]\n FOR JSON PATH, INCLUDE_NULL_VALUES), '[]')) AS [user]\n FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER), '[]')) \nAS [result]([json])\nFOR JSON PATH, INCLUDE_NULL_VALUES), '[]')",
|
|
" |--Compute Scalar(DEFINE:([Expr1010]=isnull([Expr1008],CONVERT_IMPLICIT(nvarchar(max),'[]',0))))",
|
|
" |--UDX((OPENJSON_EXPLICIT.[result_id], [Expr1007]))",
|
|
" |--Nested Loops(Left Outer Join)",
|
|
" |--Table-valued function",
|
|
" |--Compute Scalar(DEFINE:([Expr1007]=isnull([Expr1005],CONVERT_IMPLICIT(nvarchar(max),'[]',0))))",
|
|
" |--UDX(([Expr1004]))",
|
|
" |--Compute Scalar(DEFINE:([Expr1004]=isnull([Expr1001],CONVERT_IMPLICIT(nvarchar(max),'[]',0))))",
|
|
" |--UDX(([t_user1].[name]))",
|
|
" |--Clustered Index Scan(OBJECT:([master].[dbo].[user].[PK__user__3213E83F9704D3EC] AS [t_user1]))"
|
|
],
|
|
"variables": {
|
|
"synthetic": [],
|
|
"query": {},
|
|
"session": {}
|
|
}
|
|
}
|
|
|
|
Disabling Explain API
|
|
---------------------
|
|
|
|
The Explain API is part of the :ref:`Metadata API <metadata_apis>` and can only be disabled by disabling the same.
|