programing

SELECT*가 유해한 이유는 무엇입니까?

minimums 2023. 5. 18. 20:53
반응형

SELECT*가 유해한 이유는 무엇입니까?

왜?SELECT *나쁜관행? 당신이 원하는 열을 새로 추가하면 변경할 코드가 줄어들지 않을까요?

는 그것을 합니다.SELECT COUNT(*)일부 DB에서는 성능 문제가 발생합니다. 하지만 모든 열을 사용하려면 어떻게 해야 합니까?

세 가지 주요 이유가 있습니다.

  • 소비자에게 데이터를 이동하는 데 있어 비효율적입니다.*를 선택하면 응용프로그램이 실제로 작동하는 데 필요한 것보다 더 많은 열을 데이터베이스에서 검색하는 경우가 많습니다.따라서 더 많은 데이터가 데이터베이스 서버에서 클라이언트로 이동하여 액세스 속도가 느려지고 시스템의 부하가 증가할 뿐만 아니라 네트워크를 통해 이동하는 데 더 많은 시간이 소요됩니다.이는 원래 소비자가 데이터 액세스를 코딩할 때 존재하지 않았고 필요하지 않았던 기본 테이블에 새 열을 추가하는 경우에 특히 해당됩니다.

  • 인덱싱 문제입니다.쿼리를 높은 수준의 성능으로 조정하려는 시나리오를 생각해 보십시오.*를 사용할 경우 실제 필요한 것보다 더 많은 열이 반환되면 서버가 데이터를 검색하는 데 다른 방법보다 더 많은 비용이 드는 방법을 수행해야 하는 경우가 많습니다.예를 들어, 단순히 SELECT 목록의 열을 덮는 인덱스를 만들 수 없으며, 생성한 경우에도 (모든 열 [Shudder] 포함) 다음에 와서 기본 테이블에 열을 추가한 사용자는 최적화된 커버링 인덱스를 무시합니다.그리고 쉽게 명백한 이유 없이 쿼리 성능이 크게 저하될 수 있습니다.

  • 바인딩 문제.*를 선택하면 두 개의 다른 테이블에서 동일한 이름의 두 열을 검색할 수 있습니다.이로 인해 데이터 소비자가 자주 충돌할 수 있습니다.두 테이블 모두 "ID"라는 열을 포함하는 두 테이블을 조인하는 쿼리를 상상해 보십시오.소비자가 어떤 것이 무엇인지 어떻게 알 수 있습니까? SELECT *는 기본 테이블 구조가 변경될 때(적어도 일부 버전의 SQL Server에서는) 보기를 혼동할 수 있습니다. 보기가 재구성되지 않으며 반환되는 데이터는 무의미할 수 있습니다.그리고 가장 나쁜 점은 여러분이 원하는 대로 여러분의 칼럼에 이름을 붙일 수 있다는 것입니다. 하지만 다음에 오는 사람은 여러분이 이미 개발한 이름과 충돌할 칼럼을 추가하는 것에 대해 걱정해야 한다는 것을 알 방법이 없을 수도 있습니다.

하지만 SELECT*의 경우 모두 나쁜 것은 아닙니다. 저는 다음과 같은 사용 사례에 자유롭게 사용합니다.

  • 임시 쿼리입니다.특히 내가 잘 모르는 좁은 테이블에서 무언가를 디버깅하려고 할 때 SELECT *가 종종 나의 가장 친한 친구입니다.이것은 기본 열 이름이 무엇인지에 대한 많은 조사를 하지 않고도 무슨 일이 일어나고 있는지 볼 수 있도록 도와줍니다.이 값은 열 이름이 길어질수록 더 큰 "플러스"가 됩니다.

  • *가 "행"을 의미하는 경우.다음 사용 사례에서 SELECT*는 문제가 없으며, 성능 킬러라는 소문은 수년 전에 어느 정도 유효했을 수도 있는 도시 전설에 불과하지만, 지금은 그렇지 않습니다.

    SELECT COUNT(*) FROM table;
    

    이 경우 *는 "행 수를 세다"를 의미합니다.* 대신 열 이름을 사용하면 해당 열의 값이 null이 아닌 행을 카운트합니다. COUNT(*)는 을 카운트한다는 개념을 잘 이해할 수 있으며, 집계에서 NULL이 제거되어 발생하는 이상한 에지 케이스를 피할 수 있습니다.

    다음 쿼리 유형도 마찬가지입니다.

    SELECT a.ID FROM TableA a
    WHERE EXISTS (
        SELECT *
        FROM TableB b
        WHERE b.ID = a.B_ID);
    

    모든 데이터베이스에서 *는 "행"을 의미합니다.당신이 하위 질의에 무엇을 넣었는지는 중요하지 않습니다.일부 사람들은 SELECT 목록에서 b의 ID를 사용하거나 숫자 1을 사용하지만 IMO는 거의 무의미합니다.당신이 의미하는 것은 "열을 세어라"는 것이고, 그것이 *가 의미하는 것입니다.대부분의 쿼리 최적화 프로그램은 이를 알 수 있을 정도로 똑똑합니다.(솔직히 말하자면 SQL Server 및 Oracle에서만 이러한 사실을 알고 있습니다.)

SELECT 문에서 별표 문자 "*"는 쿼리와 관련된 테이블의 모든 열에 대한 단축형입니다.

성능

*속기가 더 느릴 수 있는 이유는 다음과 같습니다.

  • 모든 필드가 색인화되지 않아 전체 테이블 검색이 수행되므로 효율성이 떨어집니다.
  • 전송하기 위해 저장하는 항목SELECT *는 전체 .
  • 필요 이상의 데이터 반환
  • 가변 길이 데이터 유형을 사용하여 후행 열을 반환하면 검색 오버헤드가 발생할 수 있습니다.

유지

을 할 때SELECT *:

  • 코드베이스에 익숙하지 않은 사용자는 적절한 변경을 수행하기 전에 반환되는 열을 알기 위해 설명서를 참조해야 합니다.코드를 더 읽기 쉽게 만들고, 코드에 익숙하지 않은 사람들에게 필요한 모호성과 작업을 최소화하면 장기적으로 더 많은 시간과 노력을 절약할 수 있습니다.
  • 가 열 순서에 , 코가열순따달라면지라에서드,면,SELECT *테이블의 열 순서가 변경된 경우 발생 대기 중인 오류를 숨깁니다.
  • 쿼리를 작성할 때 모든 열이 필요하더라도 앞으로는 그렇지 않을 수 있습니다.
  • 사용법은 프로파일링을 복잡하게 만듭니다.

설계.

SELECT *안티바이러스:

  • 쿼리의 목적이 명확하지 않습니다. 응용 프로그램에서 사용하는 열이 불투명합니다.
  • 가능할 때마다 엄격한 타이핑을 사용한다는 모듈화 규칙을 위반합니다.명시적인 것이 거의 보편적으로 더 낫습니다.

"SELECT *"를 언제 사용해야 합니까?

사할수 있다니습용을 사용하는됩니다.SELECT *쿼리를 작성할 때 존재했던 모든 열과 달리 관련 테이블의 모든 열이 명시적으로 필요한 경우.데이터베이스는 내부적으로 *를 전체 열 목록으로 확장합니다. 성능 차이는 없습니다.

그렇지 않으면 쿼리에서 사용할 모든 열을 명시적으로 나열합니다. 가능하면 테이블 별칭을 사용하는 동안입니다.

지금 모든 열을 선택하려는 경우에도 다른 사용자가 하나 이상의 새 열을 추가한 후에는 모든 열을 선택하지 않을 수 있습니다.다음을 사용하여 쿼리를 작성하는 경우SELECT *실제로 해당 열이 필요하지 않아도 쿼리가 더 느리게 실행되도록 하는 텍스트 열을 추가할 수 있는 위험을 감수해야 합니다.

당신이 원하는 열을 새로 추가하면 변경할 코드가 줄어들지 않을까요?

실제로 새 열을 사용하려면 코드를 상당히 많이 변경해야 할 가능성이 있습니다.당신은 단지 저축할 뿐입니다., new_column단지 몇 글자의 타이핑.

모든 열을 원하는 경우 선택(*)과 열 이름 지정 간의 성능 차이를 확인하지 못했습니다.열 이름을 지정하는 드라이버는 코드에 어떤 열이 표시될 것인지를 명시하기 위한 것일 수 있습니다.

그러나 모든 열을 원하지 않는 경우가 많으며 선택(*)으로 인해 데이터베이스 서버에 불필요한 작업이 발생하고 네트워크를 통해 불필요한 정보가 전달될 수 있습니다.시스템 사용률이 높거나 네트워크 연결 속도가 느리지 않으면 눈에 띄는 문제가 발생하지 않을 수 있습니다.

SELECT 문에서 열 이름을 지정하면 지정된 순서대로 반환되므로 숫자 인덱스에서 안전하게 참조할 수 있습니다."SELECT *"를 사용하면 임의의 순서로 열을 수신할 수 있으므로 이름으로만 열을 안전하게 사용할 수 있습니다.데이터베이스에 추가되는 새 열을 사용하여 수행할 작업을 미리 알고 있지 않은 경우 가장 올바른 작업은 이 열을 무시하는 것입니다.데이터베이스에 추가되는 새 열을 무시하는 경우 해당 열을 검색해도 아무런 이점이 없습니다.

대부분의 경우 SELECT *는 설계 시간이 아닌 실행 시간에 응용 프로그램에서 오류를 발생시킵니다.응용프로그램의 열 변경 또는 잘못된 참조에 대한 정보를 숨깁니다.

앱과 데이터베이스 간의 결합을 줄이는 것으로 생각합니다.

냄새의 측면을 하자면, '코드 냄새'입니다.
SELECT *응용 프로그램과 스키마 간에 동적 종속성을 생성합니다.사용을 제한하는 것은 종속성을 더욱 정의할 수 있는 한 가지 방법입니다. 그렇지 않으면 데이터베이스를 변경하면 응용프로그램이 중단될 가능성이 높아집니다.

에 포함됩니다.select *이것은 편리해 보이지만 필요한 것보다 더 많은 데이터를 가져올 때 응용 프로그램 속도가 느려지고 실제로 응용 프로그램이 중단됩니다.

결과의 각 행에서 가져올 수 있는 데이터 양에는 제한이 있습니다.결과가 이 제한을 초과하도록 테이블에 필드를 추가하면 쿼리를 실행할 때 오류 메시지가 표시됩니다.

이것은 찾기 어려운 종류의 오류입니다.한 곳에서 변경을 하면 실제로 새로운 데이터를 전혀 사용하지 않는 다른 곳에서 변경이 발생합니다.사용 빈도가 낮은 쿼리일 수도 있으므로 다른 사용자가 사용할 때까지 시간이 좀 걸릴 수 있으며, 이로 인해 오류를 변경 사항에 연결하는 것이 더욱 어려워집니다.

결과에 사용할 필드를 지정하면 이러한 오버헤드 오버플로로부터 안전합니다.

저는 이것에 대한 포괄적인 규칙이 실제로 있을 수 있다고 생각하지 않습니다.많은 경우 SELECT*를 피했지만 SELECT*가 매우 유익한 데이터 프레임워크를 사용하기도 했습니다.

모든 것과 마찬가지로, 이점과 비용이 있습니다.이점 대 비용 방정식의 일부는 데이터 구조에 대한 제어 능력이라고 생각합니다.SELECT*가 잘 작동하는 경우에는 데이터 구조가 엄격하게 제어되었습니다(소매 소프트웨어). 따라서 누군가가 거대한 BLOB 필드를 테이블에 몰래 집어넣을 위험이 별로 없었습니다.

이 문서에서 인용한 자료입니다.

절대 "SELECT *"로 진행하지 마십시오.

"SELECT *"를 사용해야 하는 이유는 단 한 가지뿐입니다.

열을 추가 또는 삭제할 때 특별한 요구사항이 있고 동적 환경이 생성된 경우 응용프로그램 코드로 자동 처리됩니다.이 특별한 경우 응용 프로그램 및 데이터베이스 코드를 변경할 필요가 없으며, 이는 프로덕션 환경에 자동으로 영향을 미칩니다.이 경우 "SELECT *"를 사용할 수 있습니다.

일반적으로 당신은 당신의 결과를 맞추어야 합니다.SELECT * ...다양한 유형의 데이터 구조로 변환합니다.결과가 도착하는 순서를 지정하지 않으면 모든 항목을 올바르게 정렬하기가 까다로울 수 있습니다(더 많은 필드는 놓치기 훨씬 쉽습니다).

이렇게 하면 응용프로그램 전체에서 SQL 액세스 코드를 손상시키지 않고 다양한 이유로 테이블에 필드를 추가할 수 있습니다.

용사를 합니다.SELECT *두 개의 열만 있으면 전송되는 데이터가 필요한 것보다 훨씬 많다는 것을 의미합니다.이렇게 하면 데이터베이스 처리가 추가되고 데이터를 클라이언트로 가져오는 지연 시간이 늘어납니다.또한 로드 시 메모리를 더 많이 사용하며, 대용량 BLOB 파일과 같은 경우에는 효율성이 중요합니다.

그러나 이 외에도 테이블에 있는 열을 조회할 필요 없이 어떤 열이 로드되고 있는지 조회할 때 더 쉽게 확인할 수 있습니다.

예, 열을 추가하는 경우 더 빠르지만 대부분의 경우 쿼리를 사용하여 새 열을 수락하는 코드를 변경해야 하며, 원하지 않거나 예상치 못한 열을 받는 경우 문제가 발생할 수 있습니다.예를 들어, 모든 열을 가져온 다음 루프의 순서에 따라 변수를 할당한 다음 변수를 추가하거나, 열 순서가 변경되면(백업에서 복원할 때 발생하는 것으로 확인됨) 모든 항목이 삭제될 수 있습니다.

이것은 또한 같은 종류의 추론입니다. 왜 당신이 그것을 하고 있다면.INSERT항상 열을 지정해야 합니다.

열 이름으로 선택하면 데이터베이스 엔진이 테이블 데이터를 쿼리하지 않고 인덱스에서 데이터에 액세스할 수 있을 가능성이 높아집니다.

SELECT *는 코드가 새 데이터를 사용하거나 표시할 준비가 되어 있지 않은 경우에도 테이블에 새 열을 추가하게 되므로 데이터베이스 스키마가 변경될 경우 시스템이 예상치 못한 성능 및 기능 변경에 노출됩니다.

또한 더 실용적인 이유가 있습니다: 돈.클라우드 데이터베이스를 사용하고 처리된 데이터에 대한 비용을 지불해야 하는 경우 즉시 폐기할 데이터를 읽을 수 있는 설명이 없습니다.

: BigQuery:

쿼리 가격

쿼리 가격은 SQL 명령 및 사용자 정의 기능을 실행하는 데 드는 비용을 나타냅니다.BigQuery는 처리된 바이트 수라는 하나의 메트릭을 사용하여 쿼리를 청구합니다.

컨트롤 투영 - 선택 방지 *:

모범 사례:컨트롤 투영 - 필요한 열만 쿼리합니다.

투영은 쿼리에서 읽은 열 수를 나타냅니다.과도한 열을 투영하면 추가적인(낭비된) I/O 및 구체화(결과 쓰기)가 발생합니다.

SELECT*를 사용하는 것은 데이터를 쿼리하는 가장 비싼 방법입니다.SELECT *를 사용하면 BigQuery는 테이블의 모든 열을 전체 스캔합니다.

스키마를 설계하기 전에 요구 사항을 이해합니다(가능한 경우).

데이터에 대해 알아보기, 1) 인덱싱 2) 사용되는 스토리지 유형, 3) 벤더 엔진 또는 기능, 즉...캐슁, 인메모리 기능 4) 데이터 유형 5) 테이블 크기 6) 쿼리 빈도 7) 리소스가 공유된 경우 관련 워크로드 8)시험

요구 사항은 다양합니다.하드웨어가 예상되는 워크로드를 지원할 수 없는 경우 워크로드의 요구 사항을 제공하는 방법을 다시 평가해야 합니다.표의 추가 열에 대해 설명합니다.데이터베이스가 보기를 지원하는 경우 특정 이름이 지정된 열로 특정 데이터의 인덱싱된(?) 보기를 만들 수 있습니다(vs. select '*).데이터와 스키마를 주기적으로 검토하여 "쓰레기 반입" -> "쓰레기 배출" 증후군에 절대 걸리지 않도록 합니다.

다른 해결책이 없다고 가정하면 다음 사항을 고려할 수 있습니다.문제에는 항상 여러 가지 해결책이 있습니다.

인덱싱:*를 선택하면 테이블 검색이 실행됩니다.다양한 요인에 따라 디스크 검색 및/또는 다른 쿼리와의 경합이 발생할 수 있습니다.표가 다목적인 경우, 모든 쿼리가 수행되고 목표 시간 이하로 실행되는지 확인합니다.데이터 양이 많고 네트워크 또는 기타 리소스가 조정되지 않은 경우 이를 고려해야 합니다.데이터베이스는 공유 환경입니다.

저장소 유형.예: SSD, 디스크 또는 메모리를 사용하는 경우 I/O 시간과 시스템/CPU의 로드가 달라집니다.

DBA가 더 높은 성능을 위해 데이터베이스/테이블을 조정할 수 있습니까?어떤 이유에서건, 팀들은 선택한 '*'이 문제에 대한 최선의 해결책이라고 결정했습니다. DB나 테이블을 메모리에 로드할 수도 있습니다. (아니면... 응답이 2-3초 지연으로 응답하도록 설계되었을 수도 있습니다. -- 광고가 회사 수익을 얻기 위해 재생되는 동안...)

기준선에서 시작합니다.데이터 유형과 결과가 표시되는 방식을 이해합니다.데이터 유형이 작을수록 필드 수가 많을수록 결과 집합에 반환되는 데이터 양이 줄어듭니다.따라서 리소스를 다른 시스템 요구 사항에 사용할 수 있습니다.시스템 리소스에는 일반적으로 한계가 있습니다. '항상' 이러한 한계 아래에서 작업하여 안정성과 예측 가능한 동작을 보장합니다.

테이블/데이터의 크기입니다. '*'을 선택하면 작은 테이블에서 일반적입니다.일반적으로 메모리에 적합하며 응답 시간이 빠릅니다.다시...요구사항을 검토합니다.기능 크리프에 대한 계획을 수립합니다. 항상 현재 및 가능한 미래의 요구사항에 대해 계획을 수립합니다.

쿼리/쿼리 빈도입니다.시스템의 다른 워크로드에 주의해야 합니다.이 쿼리가 매 초마다 실행되고 테이블이 작은 경우.결과 집합을 캐시/메모리에 유지하도록 설계할 수 있습니다.그러나 쿼리가 기가바이트/테라바이트의 데이터를 사용하는 빈번한 배치 프로세스인 경우...다른 워크로드의 영향을 받지 않도록 추가 리소스를 전용하는 것이 좋습니다.

관련 워크로드.리소스가 사용되는 방식을 이해합니다.네트워크/시스템/데이터베이스/테이블/애플리케이션이 전용입니까, 아니면 공유입니까?이해관계자는 누구입니까?운영, 개발 또는 QA를 위한 것입니까?이것은 일시적인 "빠른 해결"입니까?시나리오를 테스트해 보셨습니까?오늘날 현재 하드웨어에 얼마나 많은 문제가 존재할 수 있는지 알게 될 것입니다.(예, 성능이 빠릅니다...하지만 디자인/성능은 여전히 저하됩니다.)시스템이 초당 5-10개의 쿼리를 수행하는 대신 초당 10,000개의 쿼리를 수행해야 합니까?데이터베이스 서버가 전용인지 아니면 다른 응용 프로그램이 공유 리소스에서 모니터링을 실행하는지 확인합니다.일부 애플리케이션/언어, O/S는 메모리를 100% 사용하여 다양한 증상/문제를 일으킵니다.

테스트:여러분의 이론을 시험해 보고, 여러분이 할 수 있는 한 많이 이해하세요.선택한 '*' 문제는 큰 문제일 수도 있고, 걱정할 필요도 없는 문제일 수도 있습니다.

여기에 중요한 차이점이 있습니다. 대부분의 답이 빠져있다고 생각합니다.

SELECT *문제가 되지 않습니다.의 결과 반환SELECT *문제입니다.

제 생각에 좋은 예는 다음과 같습니다.

WITH data_from_several_tables AS (
    SELECT * FROM table1_2020
        UNION ALL
    SELECT * FROM table1_2021
    ...
)
SELECT id, name, ...
FROM data_from_several_tables
WHERE ...
GROUP BY ...
...

이렇게 하면 사용 시 발생하는 모든 "문제"를 피할 수 있습니다.SELECT *대부분의 답변에 언급됨:

  • 예상보다 많은 데이터를 읽으십니까?최신 데이터베이스의 옵티마이저는 실제로 모든 열이 필요하지 않다는 것을 인식합니다.
  • 원본 테이블의 열 순서가 출력에 영향을 미칩니까?우리는 여전히 명시적으로 데이터를 선택하고 반환합니다.
  • 소비자가 SQL에서 수신하는 열을 볼 수 없습니까?작업 중인 열은 코드로 명시되어 있습니다.
  • 인덱스를 사용할 수 없습니까?다시 말하지만, 현대의 옵티마이저들은 우리가 하지 않았던 것처럼 이것을 똑같이 처리해야 합니다.SELECT *

여기에는 가독성/반제성이 있습니다. 긴 열 목록이나 필터와 같은 기타 일반적인 쿼리 절을 복제할 필요가 없습니다.사용할 때 쿼리 계획에 차이가 있다면 깜짝 놀랄 것입니다.SELECT *와 같이 ▁with▁this이▁like같.SELECT <columns>(대부분의 경우 - 중요한 경우에는 항상 실행 중인 코드를 프로파일링합니다.)

언급URL : https://stackoverflow.com/questions/3639861/why-is-select-considered-harmful

반응형