기록 기반 최적화 사용
이 가이드에서는 기록 기반 최적화의 작동 방식과 쿼리에 미치는 영향을 추정하는 방법을 설명합니다.
기록 기반 최적화 정보
기록 기반 최적화는 이미 완료된 동일하거나 유사한 쿼리 실행 정보를 자동으로 사용하여 추가 최적화를 적용하고 사용된 슬롯 시간 및 쿼리 지연 시간과 같은 쿼리 성능을 더욱 향상시킵니다. 예를 들어 첫 번째 쿼리가 실행되는 데 60초가 걸릴 수 있지만 기록 기반 최적화가 식별된 경우에는 두 번째 쿼리 실행 시간이 30초에 불과할 수 있습니다. 이 프로세스는 추가할 최적화가 없을 때까지 계속됩니다.
다음은 기록 기반 최적화가 BigQuery에서 작동하는 방식의 예시입니다.
| 실행 횟수 | 소비된 쿼리 슬롯 시간 | 참고 |
|---|---|---|
| 1 | 60 | 원래 실행. |
| 2 | 30 | 첫 번째 기록 기반 최적화가 적용되었습니다. |
| 3 | 20 | 두 번째 기록 기반 최적화가 적용되었습니다. |
| 4 | 21 | 적용할 추가 기록 기반 최적화가 없습니다. |
| 5 | 19 | 적용할 추가 기록 기반 최적화가 없습니다. |
| 6 | 20 | 적용할 추가 기록 기반 최적화가 없습니다. |
기록 기반 최적화는 쿼리 성능에 유용한 영향을 줄 것이라는 확신이 있는 경우에만 적용됩니다. 또한 최적화로 쿼리 성능이 크게 향상되지 않거나 성능이 저하될 수 있으면 해당 최적화가 취소되고 향후에 쿼리를 실행하는 데 사용되지 않습니다.
작업의 기록 기반 최적화 검토
작업의 기록 기반 최적화를 검토하려면 SQL 쿼리나 REST API 메서드 호출을 사용하면 됩니다.
SQL
쿼리를 사용하여 작업의 기록 기반 최적화를 가져올 수 있습니다.
쿼리에는 INFORMATION_SCHEMA.JOBS_BY_PROJECT 및 query_info.optimization_details 열 이름이 포함되어야 합니다.
다음 예시에서는 sample_job라는 작업의 최적화 세부정보가 반환됩니다. 기록 기반 최적화가 적용되지 않으면 NULL이 optimization_details에 생성됩니다.
SELECT
job_id,
query_info.optimization_details
FROM `PROJECT_NAME.region-LOCATION`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE job_id = 'sample_job'
LIMIT 1;
결과는 다음과 유사합니다.
-- The JSON in optimization_details has been formatted for readability.
/*------------+-----------------------------------------------------------------*
| job_id | optimization_details |
+------------+-----------------------------------------------------------------+
| sample_job | { |
| | "optimizations": [ |
| | { |
| | "semi_join_reduction": "web_sales.web_date,RIGHT" |
| | }, |
| | { |
| | "semi_join_reduction": "catalog_sales.catalog_date,RIGHT" |
| | }, |
| | { |
| | "semi_join_reduction": "store_sales.store_date,RIGHT" |
| | },
| | { |
| | "join_commutation": "web_returns.web_item" |
| | },
| | { |
| | "parallelism_adjustment": "applied" |
| | },
| | ] |
| | } |
*------------+-----------------------------------------------------------------*/
API
작업의 최적화 세부정보를 가져오려면 jobs.get 메서드를 호출하면 됩니다.
다음 예시에서 jobs.get 메서드는 전체 응답에 최적화 세부정보(optimizationDetails)를 반환합니다.
{
"jobReference": {
"projectId": "myProject",
"jobId": "sample_job"
}
}
결과는 다음과 유사합니다.
-- The unrelated parts in the full response have been removed.
{
"jobReference": {
"projectId": "myProject",
"jobId": "sample_job",
"location": "US"
},
"statistics": {
"query": {
"queryInfo": {
"optimizationDetails": {
"optimizations": [
{
"semi_join_reduction": "web_sales.web_date,RIGHT"
},
{
"semi_join_reduction": "catalog_sales.catalog_date,RIGHT"
},
{
"semi_join_reduction": "store_sales.store_date,RIGHT"
},
{
"join_commutation": "web_returns.web_item"
},
{
"parallelism_adjustment": "applied"
}
]
}
}
}
}
}
기록 기반 최적화의 영향 추정
기록 기반 최적화의 영향을 추정하려면 다음 샘플 SQL 쿼리를 사용하여 실행 시간의 예상 개선이 가장 큰 프로젝트 쿼리를 식별하면 됩니다.
WITH
jobs AS (
SELECT
*,
query_info.query_hashes.normalized_literals AS query_hash,
TIMESTAMP_DIFF(end_time, start_time, MILLISECOND) AS elapsed_ms,
IFNULL(
ARRAY_LENGTH(JSON_QUERY_ARRAY(query_info.optimization_details.optimizations)) > 0,
FALSE)
AS has_history_based_optimization,
FROM region-LOCATION.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE EXTRACT(DATE FROM creation_time) > DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
),
most_recent_jobs_without_history_based_optimizations AS (
SELECT *
FROM jobs
WHERE NOT has_history_based_optimization
QUALIFY ROW_NUMBER() OVER (PARTITION BY query_hash ORDER BY end_time DESC) = 1
)
SELECT
job.job_id,
100 * SAFE_DIVIDE(
original_job.elapsed_ms - job.elapsed_ms,
original_job.elapsed_ms) AS percent_execution_time_saved,
job.elapsed_ms AS new_elapsed_ms,
original_job.elapsed_ms AS original_elapsed_ms,
FROM jobs AS job
INNER JOIN most_recent_jobs_without_history_based_optimizations AS original_job
USING (query_hash)
WHERE
job.has_history_based_optimization
AND original_job.end_time < job.start_time
ORDER BY percent_execution_time_saved DESC
LIMIT 10;
기록 기반 최적화가 적용된 경우 위 쿼리의 결과는 다음과 비슷합니다.
/*--------------+------------------------------+------------------+-----------------------*
| job_id | percent_execution_time_saved | new_execution_ms | original_execution_ms |
+--------------+------------------------------+------------------+-----------------------+
| sample_job1 | 67.806850186245114 | 7087 | 22014 |
| sample_job2 | 66.485800412501987 | 10562 | 31515 |
| sample_job3 | 63.285605271764254 | 97668 | 266021 |
| sample_job4 | 61.134141726887904 | 923384 | 2375823 |
| sample_job5 | 55.381272089713754 | 1060062 | 2375823 |
| sample_job6 | 45.396943168036479 | 2324071 | 4256302 |
| sample_job7 | 38.227031526376024 | 17811 | 28833 |
| sample_job8 | 33.826608962725111 | 66360 | 100282 |
| sample_job9 | 32.087813758311604 | 44020 | 64819 |
| sample_job10 | 28.356416319483539 | 19088 | 26643 |
*--------------+------------------------------+------------------+-----------------------*/
이 쿼리의 결과는 기록 기반 최적화 효과에 대한 추정치일 뿐입니다. 슬롯 가용성, 시간 경과에 따른 데이터 변경, 뷰 또는 UDF 정의, 쿼리 파라미터 값의 차이를 포함하되 이에 국한되지 않는 여러 요인이 쿼리 성능에 영향을 줄 수 있습니다.
이 샘플 쿼리의 결과가 비어 있으면 기록 기반 최적화를 사용한 작업이 없거나 모든 쿼리가 최적화된 지 30일이 지난 것입니다.
이 쿼리는 total_slot_ms 및 total_bytes_billed와 같은 다른 쿼리 성능 측정항목에 적용할 수 있습니다. 자세한 내용은 INFORMATION_SCHEMA.JOBS의 스키마를 참조하세요.