소스 코드에서 SQL을 작성하는 것이 안티 패턴으로 간주됩니까?


87

다음과 같이 SQL을 응용 프로그램에 하드 코딩하는 안티 패턴으로 간주됩니까?

public List<int> getPersonIDs()
{    
    List<int> listPersonIDs = new List<int>();
    using (SqlConnection connection = new SqlConnection(
        ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
    using (SqlCommand command = new SqlCommand())
    {
        command.CommandText = "select id from Person";
        command.Connection = connection;
        connection.Open();
        SqlDataReader datareader = command.ExecuteReader();
        while (datareader.Read())
        {
            listPersonIDs.Add(Convert.ToInt32(datareader["ID"]));
        }
    }
    return listPersonIDs;
}

일반적으로 리포지토리 레이어 등이 있지만 위 코드에서 단순화하기 위해 제외했습니다.

최근에 SQL이 소스 코드로 작성되었다고 불평 한 동료로부터 피드백을 받았습니다. 나는 왜 그런지 물어볼 기회를 얻지 못했고, 그는 이제 2 주간 (아마도 더) 떨어져 있습니다. 나는 그가 다음 중 하나를 의미한다고 가정한다.

  1. LINQ
    또는
  2. SQL에 저장 프로 시저 사용

제가 맞습니까? 소스 코드에서 SQL을 작성하는 것이 안티 패턴으로 간주됩니까? 우리는이 프로젝트를 수행하는 작은 팀입니다. 저장 프로 시저의 이점 SQL 개발자가 개발 프로세스 (저장 프로 시저 작성 등)에 참여할 수 있다는 것입니다.

편집 하드 코딩 된 SQL 문에 대한 다음 링크 회담 : https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/hard-coded-sql-statements을 . SQL 문을 준비하면 어떤 이점이 있습니까?


31
"Linq 사용"및 "저장 프로 시저 사용"은 이유가 아닙니다. 그들은 단지 제안 일뿐입니다. 2 주 정도 기다렸다가 이유를 물어보십시오.
Robert Harvey

47
Stack Exchange 네트워크는 Dapper라는 마이크로 ORM을 사용합니다. Dapper 코드의 대다수가 "하드 코딩 된 SQL"(더 많거나 적은)이라고 말하는 것이 합리적이라고 생각합니다. 따라서 나쁜 습관이라면 지구상에서 가장 유명한 웹 응용 프로그램 중 하나에서 채택한 나쁜 습관입니다.
Robert Harvey

16
리포지토리에 대한 질문에 대답하기 위해 하드 코딩 된 SQL은 사용자가 어디에 배치하든 여전히 하드 코딩 된 SQL입니다. 차이점은 리포지토리가 하드 코딩 된 SQL 을 캡슐화 할 수있는 공간을 제공한다는 것 입니다. 프로그램의 나머지 부분에서 SQL의 세부 정보를 숨기는 추상화 계층입니다.
Robert Harvey

26
아니요, 코드 내의 SQL은 안티 패턴이 아닙니다. 그러나 이는 간단한 SQL 쿼리를위한 수많은 보일러 플레이트 코드입니다.
GrandmasterB

45
'소스 코드를 통해 모든 확산'과 '소스 코드'사이에 차이가있다
tofro

답변:


112

단순성을 위해 중요한 부분을 제외했습니다. 저장소는 지속성을위한 추상화 계층입니다. 지속성을 자체 계층으로 분리하여 필요할 때 지속성 기술을보다 쉽게 변경할있습니다 . 따라서, 지속성 계층 외부에 SQL을 갖는 것은 별도의 지속성 계층을 갖는 노력을 완전히 방해합니다.

결과 : SQL은 SQL 기술에 고유 한 지속성 계층 내에서 양호합니다 (예 : SQL은 a는 SQLCustomerRepository아니지만 괜찮음 MongoCustomerRepository). 퍼시스턴스 레이어 외부에서 SQL은 추상화를 중단하므로 (나에 의해) 매우 나쁜 습관으로 간주됩니다 .

LINQ 또는 JPQL과 같은 도구는 SQL의 특징을 추상화 할 수 있습니다. 저장소 외부에 LINQ-Code 또는 JPQL 쿼리가 있으면 원시 SQL과 마찬가지로 지속성 추상화가 중단됩니다.


별도 지속성 계층의 또 다른 장점은 DB 서버를 설정하지 않고도 비즈니스 로직 코드를 단위 테스트 할 수 있다는 것입니다.

언어가 지원하는 모든 플랫폼에서 재현 가능한 결과로 메모리 프로파일이 낮고 빠른 단위 테스트가 가능합니다.

MVC + Service 아키텍처에서 이는 저장소 인스턴스를 모의하고 메모리에 일부 모의 데이터를 작성하고 특정 게터가 호출 될 때 저장소가 해당 모의 데이터를 리턴하도록 정의하는 간단한 작업입니다. 그런 다음 단위 테스트 당 테스트 데이터를 정의하고 나중에 DB 정리에 대해 걱정하지 않아도됩니다.

DB에 대한 쓰기 테스트는 간단합니다. 지속성 계층에서 관련 업데이트 메소드가 호출되었는지 확인하고 해당 상황이 발생했을 때 엔티티가 올바른 상태인지 확인하십시오.


80
"지속성 기술을 바꿀 수있다"는 아이디어는 대다수의 실제 프로젝트에서 비현실적이고 불필요합니다. SQL / 관계형 DB는 MongoDB와 같은 NoSQL DB와는 완전히 다릅니다. 이에 대한 자세한 기사를 참조하십시오 . 기껏해야 NoSQL을 사용하기 시작한 프로젝트는 결국 실수를 깨닫고 RDBMS로 전환합니다. 내 경험상 비즈니스 코드에서 객체 지향 쿼리 언어 (예 : JPA-QL)를 직접 사용하도록 허용하면 최상의 결과를 얻을 수 있습니다.
Rogério

6
퍼시스턴스 레이어가 변경 될 가능성이 거의 없다면 어떻게해야합니까? 지속성 계층을 변경할 때 일대일 매핑이 없으면 어떻게됩니까? 추가적인 추상화 수준의 이점은 무엇입니까?
pllee

19
@ Rogério NoSQL 스토어에서 RDBMS로 또는 그 반대로 마이그레이션하는 것은 현실적이지 않다고 말할 수 있습니다 (기술 선택이 처음에 적합하다고 가정). 그러나 한 RDBMS에서 다른 RDBMS로 마이그레이션하는 여러 실제 프로젝트에 참여했습니다. 이 시나리오에서 캡슐화 된 지속성 계층은 확실히 이점입니다.
David

6
"실제 기술을 바꿀 수있다"는 아이디어는 실제 프로젝트 대부분에서 비현실적이고 불필요합니다. "우리 회사는 이전에 그 가정에 따라 코드를 작성했습니다. 우리는 하나가 아니라 3 개의 완전히 다른 스토리지 / 쿼리 시스템을 지원하기 위해 전체 코드베이스를 리팩터링해야했으며 3 번째와 4 번째를 고려하고 있습니다. 더 나쁜 것은, 데이터베이스가 하나 뿐인 경우에도 통합이 결여되어 모든 종류의 코드 죄가 생겼습니다.
NPSF3000

3
@ Rogério "대부분의 실제 프로젝트"를 알고 있습니까? 우리 회사에서는 대부분의 응용 프로그램이 많은 공통 DBMS 중 하나와 함께 작동 할 수 있으며 이는 대부분의 클라이언트가 기능에 관한 비 기능적 요구 사항을 가지고 있기 때문에 매우 유용합니다.
BartoszKP

55

오늘날 대부분의 표준 비즈니스 응용 프로그램은 서로 다른 책임을 가진 다른 계층을 사용합니다. 그러나 어떤 레이어는 사용 하여 응용 프로그램, 어느 계층 당신과 당신의 팀까지 인 책임이있다. 당신이 우리에게 보여준 함수에 SQL을 직접 배치하는 것이 옳은지 아닌지를 결정하기 전에 알아야 할 사항

  • 응용 프로그램의 어떤 계층에 어떤 책임이 있습니까?

  • 위의 기능은 어느 계층에서

이에 대한 "하나의 솔루션"은 없습니다. 일부 응용 프로그램에서 설계자는 ORM 프레임 워크를 사용하여 프레임 워크가 모든 SQL을 생성하도록합니다. 일부 응용 프로그램에서 설계자는 이러한 SQL을 저장 프로 시저에만 독점적으로 저장하는 것을 선호합니다. 일부 응용 프로그램의 경우 SQL이있는 수작업 지속성 (또는 리포지토리) 계층이 있으며, 다른 응용 프로그램의 경우 특정 환경에서 해당 지속성 계층에 SQL을 엄격하게 배치하여 예외를 정의하는 것이 좋습니다.

그래서 당신에 대해 생각할 필요가 무엇을 : 당신이 레이어를 원하는 또는 필요 특정 응용 프로그램에서, 그리고 어떻게 당신이 책임 원하는? "보통 리포지토리 계층을 갖고 싶습니다"라고 썼지 만, 그 계층 내에서 갖고 싶은 정확한 책임은 무엇이며, 다른 곳에서 어떤 책임을지고 싶습니까? 먼저 대답하면 스스로 질문에 대답 할 수 있습니다.


1
질문을 편집했습니다. 그것이 빛을 발산하는지 확실하지 않습니다.
w0051977

18
@ w0051977 : 당신이 게시 된 링크는 우리에 대해 아무것도 말해주지 않는 당신의 권리 응용 프로그램을? 모든 응용 프로그램에 맞는 SQL을 배치 할 위치에 대한 간단한 두뇌 교착 상태 규칙을 찾고있는 것 같습니다. 없습니다. 이 디자인 결정이다 당신 에 대해 확인해야합니다 당신 (당신의 팀과 아마 함께) 개별 응용 프로그램.
Doc Brown

7
+1. 특히 메서드의 SQL과 저장 프로 시저의 SQL간에 "하드 코딩 된"방식이나 재사용, 유지 관리 가능 등의 측면에서 실질적인 차이는 없습니다. 방법으로 절차를 수행 할 수 있습니다. 물론 프로시 저는 유용 할 수 있지만, "우리는 메소드에 SQL을 가질 수 없으므로 프로 시저에 모두 넣자"는 규칙은 별다른 이점이 없을 것입니다.

1
@ user82096 SP에 db 액세스 코드를 넣는 것은 일반적으로 내가 본 거의 모든 프로젝트에서 해 롭습니다. (MS 스택) 실제 성능 저하 (엄격한 실행 계획 캐시) 외에도 로직을 분리하여 시스템 유지 관리를 어렵게하고 앱 로직 개발자와 다른 사람들이 SP를 유지 관리했습니다. 특히 배포 슬롯 간 코드 변경이 수초의 작업과 같지만 슬롯 간 비 코드 우선 / DB 우선 스키마 마이그레이션은 약간의 골치 아픈 문제입니다.
Sentinel

33

Marstato가 좋은 대답을하지만 해설을 더 추가하고 싶습니다.

소스의 SQL은 안티 패턴이 아니지만 문제를 일으킬 수 있습니다. SQL 쿼리를 모든 폼에 드롭 된 구성 요소의 속성에 넣어야 할 때를 기억합니다. 이로 인해 상황이 정말 추악 해졌으며 쿼리를 찾기 위해 농구대를 뛰어 넘어야했습니다. 나는 작업하고있는 언어의 한계 내에서 가능한 한 데이터베이스 액세스를 중앙 집중화 할 것을 강력히 옹호했다 . 동료가이 어두운 날에 역화를 겪고있을 수 있습니다.

자, 일부 의견은 자동으로 나쁜 일처럼 벤더 잠금에 대해 이야기하고 있습니다. 그렇지 않습니다. 매년 Oracle을 사용하기 위해 6 개의 숫자 검사에 서명하는 경우 해당 데이터베이스에 액세스하는 응용 프로그램이 추가 Oracle 구문을 적절하게 사용하기를 원할 수 있습니다.그러나 최대로. 데이터베이스를 손상시키지 않는 SQL을 작성하는 "Oracle 방식"이있을 때 바닐라 ANSI SQL을 잘못 작성하는 코더가 반짝이는 데이터베이스를 손상시키는 경우에는 기쁘지 않습니다. 예, 데이터베이스를 변경하는 것이 더 어려울 수 있지만 20 년 동안 대규모 클라이언트 사이트에서 몇 번만 수행되었으며 DB2를 호스팅하는 메인 프레임이 더 이상 사용되지 않아 서비스가 중단되어 DB2-> Oracle에서 이러한 사례 중 하나가 이동하고 있음을 확인했습니다. . 그렇습니다. 벤더 잠금이지만 기업 고객에게는 Oracle 또는 Microsoft SQL Server와 같은 고가의 유능한 RDBMS를 지불 한 후 최대한 활용하는 것이 바람직합니다. 편안한 담요로 지원 계약이 있습니다. 풍부한 저장 프로 시저 구현을 사용하여 데이터베이스에 비용을 지불하는 경우

이것은 SQL 데이터베이스에 액세스하는 응용 프로그램을 작성하는 경우 다른 언어뿐만 아니라 SQL 도 배우고 쿼리 최적화도 의미합니다. 독창적으로 매개 변수가 지정된 쿼리를 사용할 수 있었을 때 거의 동일한 쿼리를 사용하여 SQL 캐시를 플러시하는 SQL 생성 코드를 작성하면 화가 날 것입니다.

변명도없고, 최대 절전 모드 벽 뒤에 숨어 있지 않습니다. 잘못 사용 된 ORM은 실제로 응용 프로그램의 성능을 저하 시킬 수 있습니다 . 몇 년 전에 Stack Overflow에 대한 질문을 본 기억이 있습니다.

최대 절전 모드에서 250,000 개의 레코드를 반복하여 몇 가지 속성 값을 확인하고 특정 조건과 일치하는 개체를 업데이트합니다. 속도가 조금 느립니다. 속도를 높이려면 어떻게해야합니까?

"업데이트 테이블 SET field1 = 여기서 field2는 True이고 Field3> 100"은 어떻습니까? 250,000 개의 객체를 생성하고 처리하는 것이 문제 일 수 있습니다.

즉, 사용하기에 적합하지 않은 경우에는 최대 절전 모드를 무시하십시오. 데이터베이스를 이해하십시오.

따라서 요약하면 코드에 SQL을 포함시키는 것은 나쁜 습관이 될 수 있지만 SQL을 포함시키지 않으려는 경우 훨씬 더 나쁜 일이 발생할 수 있습니다.


5
나는 "공급 업체 잠금"이 나쁜 것이라고 말하지 않았다. 나는 그것이 절충안과 함께 제공된다고 말했습니다. xaaS로서 db를 사용하는 오늘날의 시장에서 자체 호스팅 db를 실행하기위한 이러한 오래된 계약 및 라이센스는 점점 더 드물어 질 것입니다. 10 년 전과 비교하여 벤더 A에서 B로 db를 변경하는 것이 훨씬 쉬워졌습니다. 의견을 읽으면 데이터 저장소의 모든 기능을 활용하는 것이 바람직하지 않습니다. 따라서 특정 벤더 세부 사항을 벤더에 구애받지 않는 무언가 (앱)에 쉽게 넣을 수 있습니다. 우리는 SOLiD를 따라 코드를 단일 데이터 스토리지에 고정하기 위해 노력하고 있습니다. 별거 아님
Laiv

2
이것은 좋은 대답입니다. 종종 올바른 접근 방식은 최악의 가능한 코드가 작성되는 경우 가장 나쁜 상황을 초래하는 접근 방식입니다. 최악의 ORM 코드는 최악의 내장 SQL보다 훨씬 나쁩니다.
jwg

@Laiv 좋은 점 PaaS는 약간의 게임 체인저입니다. 그 의미에 대해 더 많이 생각해야합니다.
mcottle

3
@jwg 나는 평균 ORM 코드가 평균 내장 SQL보다 낮다. :)
mcottle

@macottle 평균 이하의 내장 SQL이 ORM을 작성하는 사람의 평균보다 ppl에 의해 작성되었다고 가정합니다. 내가 의심하는 것 많은 개발자들은 먼저 왼쪽 체크 인 whitout을 먼저 작성할 수 없습니다.
Laiv

14

예, SQL 문자열을 응용 프로그램 코드로 하드 ​​코딩하는 것은 일반적으로 안티 패턴입니다.

생산 코드에서 이것을 보며 수년간 개발 한 공차를 따로 떼어 봅시다. 동일한 파일에서 다른 구문과 완전히 다른 언어를 혼합하는 것은 일반적으로 바람직한 개발 기술이 아닙니다. 이것은 여러 언어에 문맥 적 의미를 부여하도록 설계된 Razor와 같은 템플릿 언어와 다릅니다. Sava B.가 아래 주석에서 언급 했듯이 C # 또는 다른 응용 프로그램 언어 (Python, C ++ 등)의 SQL은 다른 문자열이므로 의미 적으로 의미가 없습니다. 대부분의 경우 하나 이상의 언어를 혼합 할 때도 동일하게 적용되지만 C의 인라인 어셈블리, HTML에서 CSS의 작고 이해하기 쉬운 스 니펫 (CSS는 HTML과 혼합되도록 설계되어 있음)과 같이 수용 가능한 상황이 있습니다. ), 다른 사람.

클린 코드 : Robert C. Martin, pg.  288 (로버트 C. Martin은 언어 혼합, Clean Code , 17 장, "코드 냄새 및 휴리스틱 스", 288 페이지)

이 응답을 위해 SQL에 초점을 맞출 것입니다 (질문에서 요청한대로). SQL을 일관된 분리 된 문자열 집합으로 저장할 때 다음과 같은 문제가 발생할 수 있습니다.

  • 데이터베이스 논리를 찾기가 어렵습니다. 모든 SQL 문을 찾기 위해 무엇을 검색합니까? "SELECT", "UPDATE", "MERGE"등이있는 문자열?
  • 동일하거나 유사한 SQL의 리팩토링 사용이 어려워집니다.
  • 다른 데이터베이스에 대한 지원을 추가하는 것은 어렵습니다. 어떻게 이것을 달성 할 수 있습니까? 각 데이터베이스에 대해 if..then 문을 추가하고 모든 쿼리를 메소드에 문자열로 저장합니까?
  • 개발자는 다른 언어로 된 문장을 읽고 메소드의 목적에서 메소드의 구현 세부 사항 (데이터 검색 방법 및 위치)으로 초점이 이동함에 따라주의가 산만 해집니다.
  • 한 줄짜리 문제는 그다지 큰 문제가되지 않지만 명령문이 더욱 복잡해지면 인라인 SQL 문자열이 분리되기 시작합니다. 113 라인으로 무엇을합니까? 방법에 113 줄을 모두 넣습니까?
  • 개발자는 SQL 편집기 (SSMS, SQL Developer 등)와 소스 코드간에 쿼리를 어떻게 효율적으로 앞뒤로 이동합니까? C #의 @접두사가 이것을 쉽게 만들어 주지만 각 SQL 줄을 인용하고 줄 바꿈을 피하는 많은 코드를 보았습니다. "SELECT col1, col2...colN"\ "FROM painfulExample"\ "WHERE maintainability IS NULL"\ "AND modification.effort > @necessary"\
  • SQL을 주변 애플리케이션 코드와 정렬하는 데 사용되는 들여 쓰기 문자는 각 실행마다 네트워크를 통해 전송됩니다. 이것은 소규모 응용 프로그램에는 중요하지 않지만 소프트웨어 사용이 증가함에 따라 더해질 수 있습니다.

전체 ORM (Entity Framework 또는 Hibernate와 같은 객체 관계형 매퍼)은 응용 프로그램 코드에서 임의로 페퍼 SQL을 제거 할 수 있습니다. SQL과 리소스 파일을 사용하는 것은 단지 예일뿐입니다. ORM, 헬퍼 클래스 등은 모두보다 깨끗한 코드의 목표를 달성하는 데 도움이 될 수 있습니다.

이전 답변에서 Kevin이 말했듯이 작은 프로젝트에서는 코드의 SQL을 사용할 수 있지만 큰 프로젝트는 작은 프로젝트로 시작하며 대부분의 팀이 되돌아 갈 수있는 가능성은 종종 코드 크기에 반비례합니다.

프로젝트에서 SQL을 유지하는 간단한 방법이 많이 있습니다. 내가 자주 사용하는 방법 중 하나는 각 SQL 문을 Visual Studio 리소스 파일 (일반적으로 "sql")에 넣는 것입니다. 도구에 따라 텍스트 파일, JSON 문서 또는 기타 데이터 소스가 합리적 일 수 있습니다. 경우에 따라 SQL 문자열을 적용하기위한 별도의 클래스가 최선의 선택 일 수 있지만 위에서 설명한 일부 문제가있을 수 있습니다.

SQL 예 : 어느 것이 더 우아해 보이는가? :

using(DbConnection connection = Database.SystemConnection()) {
    var eyesoreSql = @"
    SELECT
        Viewable.ViewId,
        Viewable.HelpText,
        PageSize.Width,
        PageSize.Height,
        Layout.CSSClass,
        PaginationType.GroupingText
    FROM Viewable
    LEFT JOIN PageSize
        ON PageSize.Id = Viewable.PageSizeId
    LEFT JOIN Layout
        ON Layout.Id = Viewable.LayoutId
    LEFT JOIN Theme
        ON Theme.Id = Viewable.ThemeId
    LEFT JOIN PaginationType
        ON PaginationType.Id = Viewable.PaginationTypeId
    LEFT JOIN PaginationMenu
        ON PaginationMenu.Id = Viewable.PaginationMenuId
    WHERE Viewable.Id = @Id
    ";
    var results = connection.Query<int>(eyesoreSql, new { Id });
}

된다

using(DbConnection connection = Database.SystemConnection()) {
    var results = connection.Query<int>(sql.GetViewable, new { Id });
}

SQL은 항상 쉽게 찾을 수있는 파일 또는 그룹화 된 파일 세트에 있으며, 각각 파일의 사용법보다는 설명이 포함 된 설명 이름을 가지고 있으며 각각은 애플리케이션 코드의 흐름을 방해하지 않는 주석을위한 공간이 있습니다. :

리소스의 SQL

이 간단한 방법은 독방 쿼리를 실행합니다. 내 경험상, "외국어"의 사용이 더욱 정교 해짐에 따라 혜택이 확대됩니다. 리소스 파일을 사용하는 것은 단지 예일뿐입니다. 언어 (이 경우 SQL) 및 플랫폼에 따라 다른 방법이 더 적절할 수 있습니다.

이 방법과 다른 방법은 다음과 같은 방식으로 위 목록을 해결합니다.

  1. 데이터베이스 코드는 이미 중앙 집중식이기 때문에 쉽게 찾을 수 있습니다. 더 큰 프로젝트에서는 like-SQL을 별도의 파일 (예 :) 폴더 아래에 별도의 파일로 그룹화하십시오 SQL.
  2. 두 번째, 세 번째 등의 데이터베이스 지원이 더 쉽습니다. 각 데이터베이스의 고유 한 명령문을 리턴하는 인터페이스 (또는 다른 언어 추상화)를 작성하십시오. 각 데이터베이스에 대한 return SqlResource.DoTheThing;구현은 다음 과 유사한 명령문에 지나지 않습니다. 사실, 이러한 구현은 리소스를 건너 뛰고 문자열에 SQL을 포함 할 수 있지만 위의 일부 (전부는 아님) 문제가 여전히 발생합니다.
  3. 리팩토링은 간단합니다. 동일한 리소스를 재사용하십시오. 몇 가지 형식 문을 사용하여 다른 DBMS 시스템에 대해 동일한 리소스 항목을 오랫동안 사용할 수도 있습니다. 나는 이것을 자주한다.
  4. 2 차 언어를 사용하면 예를 들어 더 난해한 것이 아닌 설명적인 이름을 사용할 수 있습니다.sql.GetOrdersForAccountSELECT ... FROM ... WHERE...
  5. SQL 문은 크기와 복잡성에 관계없이 한 줄로 소환됩니다.
  6. SSMS 및 SQL Developer와 같은 데이터베이스 도구간에 수정이나 신중한 복사없이 SQL을 복사하여 붙여 넣을 수 있습니다. 따옴표가 없습니다. 후행 백 슬래시가 없습니다. 특히 Visual Studio 리소스 편집기의 경우 한 번의 클릭으로 SQL 문이 강조 표시됩니다. Ctrl + C를 누른 다음 SQL 편집기에 붙여 넣습니다.

리소스에서 SQL을 생성하는 것이 빠르므로 리소스 사용을 코드 내 SQL과 혼합 할 수있는 자극이 거의 없습니다.

선택한 방법에 관계없이 언어를 혼합하면 일반적으로 코드 품질이 저하됩니다. 여기에 설명 된 일부 문제와 솔루션이 개발자가 적절한 경우이 코드 냄새를 제거하는 데 도움이되기를 바랍니다.


13
나는 이것이 소스 코드에 SQL이 있다는 나쁜 비판에 너무 많은 초점을 맞추고 있다고 생각합니다. 같은 파일에 두 개의 다른 언어가 있다고해서 반드시 끔찍한 것은 아닙니다. 그것은 그들이 어떻게 관련되고 그것들이 각각 어떻게 제시되는지와 같은 많은 것들에 달려 있습니다.
jwg

9
"동일한 파일에서 다른 구문과 완전히 다른 언어를 혼합"이것은 끔찍한 주장입니다. Razor보기 엔진과 HTML, CSS 및 Javascript에도 적용됩니다. 당신의 그래픽 소설을 사랑하십시오!
Ian Newson

4
이것은 단지 다른 곳으로 복잡성을 밀어 넣습니다. 예. 개발자가 유지 관리 목적으로 탐색해야하는 간접적 인 추가 비용으로 인해 원래 코드가 더 깨끗합니다. 이 작업을 수행하는 실제 이유는 각 SQL 문이 코드의 여러 위치에서 사용 된 경우입니다. 그런 식으로 다른 일반 리팩토링 ( "추출 방법")과 크게 다르지 않습니다.
Robert Harvey

3
더 명확하게 말하면, 이것은 "SQL 문자열로 무엇을해야합니까?"라는 질문에 대한 대답이 아니며 "충분히 복잡한 문자열 컬렉션으로 무엇을해야합니까?"라는 질문에 대한 답이기도합니다. 당신의 대답은 우연히 해결됩니다.
Robert Harvey

2
@RobertHarvey : 나는 우리의 경험이 다르다는 것을 확신하지만, 내 생각에 문제의 추상화가 대부분의 경우 승리라는 것을 알았습니다. 몇 년 동안 이리저리 해왔 던 추상화 트레이드 오프를 확실히 다듬을 것이며 언젠가는 SQL을 코드에 다시 넣을 수도 있습니다. YMMV. :) 마이크로 서비스는 훌륭 할 수 있다고 생각하며 SQL 응용 프로그램 (SQL을 전혀 사용하지 않는 경우)과 SQL 세부 정보를 너무 일반적으로 분리합니다. 나는 "나의 특정한 방법을 사용하라"는 말을 덜하고 "일반적으로 기름과 물을 섞지 않는다"는 것을 더 옹호한다.
Charles Burns

13

따라 다릅니다. 작동 할 수있는 여러 가지 접근 방식이 있습니다.

  1. SQL을 모듈화하고 SQL을 별도의 클래스, 함수 또는 패러다임이 사용하는 추상화 단위로 분리 한 다음 응용 프로그램 논리를 사용하여 호출하십시오.
  2. 복잡한 SQL을 모두보기로 이동 한 다음 응용 프로그램 논리에서 매우 간단한 SQL 만 수행하므로 모듈화 할 필요가 없습니다.
  3. 객체 관계형 매핑 라이브러리를 사용하십시오.
  4. YAGNI, 응용 프로그램 논리에 직접 SQL을 작성하십시오.

종종 그렇듯이 프로젝트에서 이미 이러한 기술 중 하나를 선택한 경우 나머지 프로젝트와 일관성이 있어야합니다.

(1)과 (3)은 데이터베이스를 다른 공급 업체로 교체하는 경우 응용 프로그램이 계속해서 기본 연기 테스트를 컴파일하고 통과한다는 의미에서 응용 프로그램 논리와 데이터베이스 간의 독립성을 유지하는 데 비교적 우수합니다. 그러나 대부분의 공급 업체는 SQL 표준을 완전히 준수하지 않으므로 공급 업체를 다른 공급 업체로 교체하려면 사용하는 기술에 관계없이 광범위한 테스트 및 버그 사냥이 필요할 수 있습니다. 나는 이것이 사람들이 생각하는 것만 큼 큰 일이라고 회의적이다. 데이터베이스 변경은 기본적으로 현재 데이터베이스를 필요에 맞게 얻을 수없는 경우 최후의 수단입니다. 이 경우 데이터베이스를 잘못 선택했을 수 있습니다.

(1)과 (3) 사이의 선택은 주로 ORM을 얼마나 좋아하는지의 문제입니다. 내 생각에 그들은 과용되었다. 행은 오브젝트가 ID를 갖는 방식으로 ID를 가지지 않기 때문에 관계형 데이터 모델을 잘 나타내지 않습니다. 고유 제약 조건, 조인과 관련하여 문제가 발생할 수 있으며 ORM의 힘에 따라 좀 더 복잡한 쿼리를 표현하는 데 어려움이있을 수 있습니다. 반면, (1) 아마도 ORM보다 훨씬 더 많은 코드가 필요할 것입니다.

(2) 내 경험으로는 거의 볼 수 없습니다. 문제는 많은 상점들이 SWE가 데이터베이스 스키마를 직접 수정하는 것을 금지한다는 것입니다 ( "DBA의 일이기 때문에"). 이것은 반드시 그 자체가 나쁜 것은 아닙니다. 스키마 변경은 문제를 일으킬 가능성이 크므로 신중하게 배포해야합니다. 그러나 (2)가 효과를 발휘하기 위해서는 SWE가 최소한 관료주의를 최소화하거나 전혀 갖지 않으면 서 새로운 견해를 도입하고 기존 견해의지지 질문을 수정할 수 있어야합니다. 귀하의 직장에서 그렇지 않은 경우, (2) 아마 효과가 없을 것입니다.

반면에 (2)가 작동하면 응용 프로그램 코드 대신 SQL에서 관계형 논리를 유지하기 때문에 대부분의 다른 솔루션보다 훨씬 낫습니다. 범용 프로그래밍 언어와 달리 SQL은 관계형 데이터 모델을 위해 특별히 설계되었으므로 복잡한 데이터 쿼리 및 변환을보다 잘 표현할 수 있습니다. 데이터베이스를 변경할 때 뷰를 나머지 스키마와 함께 이식 할 수도 있지만 이러한 이동은 더 복잡해집니다.

읽기의 경우 저장 프로시 저는 기본적으로 (2)의 crappier 버전입니다. 이 용량을 권장하지는 않지만 데이터베이스가 업데이트 가능한 뷰를 지원하지 않거나 한 번에 단일 행을 삽입하거나 업데이트하는 것보다 복잡한 작업을 수행 해야하는 경우 쓰기를 원할 수 있습니다 (예 : 트랜잭션, 읽기 및 쓰기 등). 트리거를 사용하여 저장 프로 시저를 뷰에 연결할 수 있습니다 (예 :CREATE TRIGGER trigger_name INSTEAD OF INSERT ON view_name FOR EACH ROW EXECUTE PROCEDURE procedure_name;)이지만 이것이 실제로 좋은 아이디어인지에 대한 의견은 상당히 다릅니다. 제안자는 응용 프로그램이 가능한 한 간단하게 실행하는 SQL을 유지한다고 알려줍니다. Detractors는 이것이 허용 할 수없는 수준의 "마법"이며 응용 프로그램에서 직접 프로 시저를 실행해야한다고 알려줍니다. 나는 당신의 저장 프로 시저가 보이는 나처럼 많은 역할을하는 경우이 더 좋은 생각이다라고 말하고 싶지만 INSERT, UPDATEDELETE, 그리고 나쁜 생각은 뭔가 다른 일을하는 경우. 궁극적으로 어떤 스타일이 더 적합한 지 스스로 결정해야합니다.

(4)는 해결책이 아닙니다. 소규모 프로젝트 또는 데이터베이스와 산발적으로 만 상호 작용하는 대규모 프로젝트에 유용합니다. 그러나 SQL이 많은 프로젝트의 경우 애플리케이션 주위에 동일한 쿼리가 중복되거나 유사하게 분산되어 가독성과 리팩토링을 방해 할 수 있으므로 좋지 않습니다.


작성된 2는 기본적으로 읽기 전용 데이터베이스를 가정합니다. 저장 프로시 저는 수정 된 쿼리에 일반적이지 않았습니다.
jpmc26

@ jpmc26 : 괄호로 된 글을 다룹니다 ...이 답변을 개선하기위한 구체적인 권장 사항이 있습니까?
Kevin

흠. 답변을 마치고 산만 해지기 전에 의견을 제시 한 것에 대해 사과드립니다. 그러나 업데이트 가능한 뷰는 테이블이 업데이트되는 위치를 추적하기가 다소 어렵습니다. 메커니즘에 관계없이 테이블에서 직접 업데이트를 제한하면 코드 논리를 이해하는 데 이점이 있습니다. 로직을 DB로 제한하는 경우 저장 프로 시저 없이는이를 적용 할 수 없습니다. 또한 단일 호출로 여러 작업을 수행 할 수 있다는 장점이 있습니다. 결론 : 나는 당신이 그들에 대해 너무 열심히해야한다고 생각하지 않습니다.
jpmc26

@ jpmc26 : 공평합니다.
Kevin

8

소스 코드에서 SQL을 작성하는 것이 안티 패턴으로 간주됩니까?

반드시 그런 것은 아닙니다. 여기에서 모든 주석을 읽으면 소스 코드에서 SQL 문을 하드 코딩하기위한 유효한 인수를 찾을 수 있습니다.

문을 어디에 두어야하는지 문제가 발생합니다 . 프로젝트 전체에 SQL 문을 배치하면 일반적으로 우리가 따르려고 노력하는 일부 SOLID 원칙을 무시하게 될 것입니다.

그가 의미한다고 가정; 어느 한 쪽:

1) LINQ 사용

또는

2) SQL에 대해 스토어드 프로 시저 사용

우리는 그가 무엇을 의미하는지 말할 수 없습니다. 그러나 우리는 추측 할 수 있습니다. 예를 들어, 가장 먼저 떠오르는 것은 벤더 잠금입니다 . SQL 문을 하드 코딩하면 응용 프로그램을 DB 엔진에 밀접하게 연결할 수 있습니다. 예를 들어, ANSI와 호환되지 않는 공급 업체의 특정 기능을 사용합니다.

이것은 반드시 잘못되거나 나쁘지는 않습니다. 나는 단지 사실을 가리키고 있습니다.

SOLID 원칙과 공급 업체 잠금을 무시하면 무시할 수있는 부정적인 결과가 발생할 수 있습니다. 그렇기 때문에 보통 팀과 함께 앉아 의심을 폭로하는 것이 좋습니다.

저장 프로 시저의 장점 SQL 개발자가 개발 프로세스 (저장 프로 시저 작성 등)에 참여할 수 있다는 이점이 있습니다.

저장 프로 시저의 장점과는 아무런 관련이 없다고 생각합니다. 또한 동료가 하드 코딩 된 SQL을 싫어하는 경우 비즈니스를 저장 프로 시저로 옮기면 그를 싫어할 것입니다.

편집 : 다음 링크는 하드 코딩 된 SQL 문에 대해 설명합니다 :  https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/hard-coded-sql-statements . SQL 문을 준비하면 어떤 이점이 있습니까?

예. 포스트는 준비된 진술 의 장점을 열거합니다 . 일종의 SQL 템플릿입니다. 문자열 연결보다 안전합니다. 그러나 게시물은 당신이 이런 식으로 가도록 격려하거나 당신이 옳다는 것을 확인하지 않습니다. 안전하고 효율적인 방식으로 하드 코딩 된 SQL을 사용하는 방법에 대해서만 설명합니다.

요약하면 먼저 동료에게 물어보십시오. 메일을 보내거나 전화를 겁니다. 그가 대답하든 말든 팀과 함께 앉아 의심을 폭로하십시오. 요구 사항에 가장 적합한 솔루션을 찾으십시오. 읽은 내용에 따라 잘못된 가정을하지 마십시오.


1
감사. "SQL 문을 코딩하면 응용 프로그램을 db 엔진에 단단히 연결할 수 있습니다."+1 그가 SQL이 아닌 SQL Server를 참조하는 경우, 즉 dbConnection 대신 SQLConnection을 사용하는 경우 방황합니다. dbCommand가 아닌 SQLCommand 및 dbDataReader가 아닌 SQLDataReader입니다.
w0051977

아니요. ANSI가 아닌 표현식의 사용법을 언급하고있었습니다. 예를 들어 : select GETDATE(), ....GETDATE ()는 SqlServer의 날짜 함수입니다. 다른 엔진에서, 함수는 다른 이름, 다른 표현을 가지고 있습니다.
Laiv

14
"공급 업체 잠금"... 개인 / 기업이 실제로 기존 제품의 데이터베이스를 다른 RDBMS로 얼마나 자주 마이그레이션합니까? ORM을 독점적으로 사용하는 프로젝트에서도 이런 일이 발생하는 것을 본 적이 없습니다. 일반적으로 요구가 바뀌었기 때문에 소프트웨어는 처음부터 다시 작성됩니다. 따라서 이것에 대해 생각하는 것은 나에게 "조기 최적화"와 거의 비슷합니다. 예, 완전히 주관적입니다.
Olivier Grégoire 16:15에

1
나는 얼마나 자주 발생하는지 상관하지 않습니다. 신경 쓰지 않을 수 있습니다. 그린 필드 프로젝트에서 db로부터 추상화 된 DAL을 구현하는 비용은 거의 0입니다. 가능한 마이그레이션은 그렇지 않습니다. ORM에 대한 주장은 매우 약합니다. ORM은 최대 절전 모드가 녹색 인 15 년 전과 다릅니다. 내가 본 것은 많은 "기본"구성과 훨씬 더 나쁜 데이터 모델 디자인입니다. 다른 많은 도구와 마찬가지로 많은 사람들이 "시작하기"자습서를 수행하며 실제로 수행되는 작업은 신경 쓰지 않습니다. 도구는 문제가 아닙니다. 문제는 누가 언제 어떻게 사용해야하는지 모르는 것입니다.
Laiv

다른 한편으로, 벤더 잠금은 반드시 나쁘지는 않습니다. 내가 물었다면 내가 싫어한다고 말할 입니다. 그러나 나는 이미 Spring, Tomcat 또는 JBoss 또는 Websphere에 잠겨 있습니다 (아직 더 나쁩니다). 내가 피할 수있는 사람들은 난 그냥 그것으로 살 수없는 사람들. 선호의 문제입니다.
Laiv

3

나는 그것이 나쁜 습관이라고 생각합니다. 다른 사람들은 모든 데이터 액세스 코드를 자체 계층으로 유지하는 이점을 지적했습니다. 당신은 그것을 찾아 다닐 필요가 없으며, 최적화하고 테스트하기가 더 쉽습니다 ... 그러나 그 계층 내에서도 ORM 사용, sprocs 사용 또는 SQL 쿼리를 문자열로 포함하는 몇 가지 선택이 있습니다. SQL 쿼리 문자열이 최악의 옵션이라고 말할 수 있습니다.

ORM을 사용하면 개발이 훨씬 쉬워지고 오류 발생 가능성이 줄어 듭니다. EF를 사용하면 모델 클래스를 작성하기 만하면 스키마를 정의 할 수 있습니다 (어쨌든 이러한 클래스를 작성해야했습니다). LINQ로 쿼리하는 것은 쉬운 일입니다. 종종 sproc을 작성하고 유지해야하는 2 줄의 c #을 사용하면됩니다. IMO는 생산성과 유지 보수성 측면에서 코드가 적고 문제가 적을 때 큰 이점이 있습니다. 그러나 수행중인 작업을 알고 있더라도 성능 오버 헤드가 있습니다.

Sproc (또는 함수)이 다른 옵션입니다. 여기서는 SQL 쿼리를 수동으로 작성합니다. 그러나 적어도 당신은 그들이 정확하다는 것을 확신합니다. .NET에서 작업하는 경우 SQL이 유효하지 않으면 Visual Studio에서 컴파일러 오류가 발생합니다. 대단하다. 일부 열을 변경하거나 제거하고 일부 쿼리가 유효하지 않은 경우 적어도 컴파일 시간 동안 열에 대해 찾을 가능성이 큽니다. 또한 자체 파일에서 sprocs를 유지 관리하는 것이 더 쉽습니다. 구문 강조, 자동 완성 등을 얻을 수 있습니다.

쿼리가 sproc로 저장된 경우 응용 프로그램을 다시 컴파일하고 다시 배포하지 않고도 쿼리를 변경할 수 있습니다. SQL의 무언가가 깨져 있음을 알게되면 DBA는 앱 코드에 액세스 할 필요없이 그것을 고칠 수 있습니다. 일반적으로 쿼리가 문자열 리터럴 인 경우 dbas는 거의 쉽게 작업을 수행 할 수 없습니다.

문자열 리터럴 인 SQL 쿼리는 데이터 액세스 C # 코드를 읽기 어렵게 만듭니다.

경험상 마법 상수는 좋지 않습니다. 여기에는 문자열 리터럴이 포함됩니다.


DBA가 애플리케이션을 업데이트하지 않고 SQL을 변경하도록 허용하면 애플리케이션이 별도로 개발되고 별도로 배치 된 두 엔티티로 효과적으로 분할됩니다. 이제 그 사이의 인터페이스 계약을 관리하고 상호 의존적 변경의 릴리스를 동기화하는 등의 작업이 필요합니다. 이는 좋은 일이거나 나쁜 일이지만 "모든 SQL을 한 곳에 두는 것"보다 훨씬 큽니다. 건축 결정에 도달.
IMSoP

2

반 패턴이 아닙니다 (이 답변은 위험에 가깝습니다). 그러나 코드 형식이 중요하며 SQL 문자열은 형식을 지정하여 코드를 사용하는 코드와 명확하게 구분되어야합니다. 예를 들어

    string query = 
    @"SELECT foo, bar
      FROM table
      WHERE id = @tn";

7
이것에서 가장 눈에 띄는 문제는 그 가치 42의 근원입니다. 해당 값을 문자열에 연결하고 있습니까? 그렇다면 어디에서 왔습니까? SQL 삽입 공격을 완화하기 위해 어떻게 제거 되었습니까? 이 예에 매개 변수화 된 쿼리가 표시되지 않는 이유는 무엇입니까?
Craig

방금 서식을 표시하려고했습니다. 죄송합니다. 매개 변수를 잊어 버렸습니다. 이제 참조 후 고정 msdn.microsoft.com/library/bb738521(v=vs.100).aspx
rleir

형식화의 중요성으로 +1이지만 SQL 문자열은 형식화에 관계없이 코드 냄새가납니다.
찰스 번즈

1
ORM 사용을 주장합니까? 소규모 프로젝트의 경우 ORM을 사용하지 않을 때는 Embedded SQL이 포함 된 'shim'클래스를 사용합니다.
rleir

SQL 문자열은 코드 냄새가 아닙니다. ORM이 없으면 관리자 및 설계자로서 유지 보수 및 때로는 성능상의 이유로 SP를 통해 권장합니다.
Sentinel

1

나는 당신의 동료가 무엇을 의미하는지 말할 수 없습니다. 그러나 나는 이것에 대답 할 수 있습니다 :

SQL 문을 준비하면 어떤 이점이 있습니까?

. 바인드 된 변수와 함께 준비된 명령문을 사용하는 것이 SQL 주입 에 대한 권장 방어 이며, 이는 10 년 이상 웹 애플리케이션에 대한 단일 보안 위험으로 남아 있습니다 . 이 공격은 거의 10 년 전에 웹 만화 에 등장한 것이 일반적 이며 효과적인 방어 수단이 구축 된 시점입니다.

... 그리고 쿼리 문자열의 잘못된 연결에 대한 가장 효과적인 방어는 처음에는 쿼리를 문자열로 나타내는 것이 아니라 형식 안전 쿼리 API를 사용하여 쿼리를 작성하는 것입니다. 예를 들어, QueryDSL을 사용하여 Java로 쿼리를 작성하는 방법은 다음과 같습니다.

List<UUID> ids = select(person.id).from(person).fetch();

보시다시피 여기에 단일 문자열 리터럴이 없으므로 SQL 삽입이 불가능합니다. 또한이 코드를 작성할 때 코드 완성이 있었고 IDE에서 ID 열의 이름을 바꾸도록 선택하면 리팩터링 할 수 있습니다. 또한 person변수에 액세스 할 수 있는 IDE를 요청하여 person 테이블에 대한 모든 쿼리를 쉽게 찾을 수 있습니다 . 아, 그리고 코드보다 눈이 짧고 쉽다는 것을 알았습니까?

C #에서도 이와 같은 것을 사용할 수 있다고 가정 할 수 있습니다. 예를 들어, 나는 LINQ에 대해 큰 것들을 듣는다.

요약하면, 쿼리를 SQL 문자열로 표시하면 IDE가 쿼리 작성 및 리팩토링을 의미있게 지원하지 못하고 컴파일 시간에서 런타임까지 구문 및 유형 오류의 감지를 지연 시키며 SQL 인젝션 취약점의 원인이됩니다 [1]. 따라서 소스 코드에서 SQL 문자열을 원하지 않는 유효한 이유가 있습니다.

[1] : 예, 준비된 명령문을 올바르게 사용하면 SQL 삽입이 방지됩니다. 그러나이 스레드의 또 다른 대답은 논평자가 이것을 지적 할 때까지 SQL 주입에 취약하여 필요할 때마다 주니어 프로그래머가 올바르게 사용한다는 확신을 얻지 못합니다 ...


명확하게 : 준비된 문을 사용해도 SQL 삽입을 막을 수는 없습니다. 바운드 변수와 함께 준비된 명령문을 사용하면됩니다. 신뢰할 수없는 데이터로 작성된 준비된 명령문을 사용할 수 있습니다.
Andy Lester

1

여기에 많은 훌륭한 답변이 있습니다. 이미 말한 것 외에도 다른 것을 추가하고 싶습니다.

인라인 SQL을 안티 패턴으로 사용하는 것은 고려하지 않습니다. 그러나 반 패턴을 고려하는 것은 모든 프로그래머가 자신의 일을하는 것입니다. 공통 표준에 따라 팀을 결정해야합니다. 모든 사람이 linq를 사용하고 있다면 linq를 사용하고 모든 사람이 뷰와 저장 프로 시저를 사용하고 있다면 그렇게합니다.

항상 열린 마음을 유지하고 교리에 빠지지 마십시오. 상점이 "linq"상점 인 경우이를 사용하십시오. linq가 절대 작동하지 않는 곳을 제외하고. (하지만 99.9 %의 시간이되어서는 안됩니다.)

그래서 내가 할 일은 코드베이스에서 코드를 연구하고 동료들이 어떻게 작동하는지 확인하는 것입니다.


좋은 지적 +1 지원 가능성은 대부분의 다른 고려 사항보다 중요하므로 너무 영리하지 마십시오. ORM 상점이라면 ORM이 답이 아니고 직접 SQL을 작성해야하는 경우를 잊지 마십시오. 조기에 최적화하지는 않지만이 경로를 따라야 할 때 사소한 응용 프로그램에는 시간이 있습니다.
mcottle

0

코드는 데이터베이스와 나머지 코드 사이에있는 데이터베이스 상호 작용 계층과 비슷합니다. 실제로 그렇다면 이것은 안티 패턴 이 아닙니다 .

이 방법은 OP가 다르게 생각하더라도 (일반 데이터베이스 액세스, 다른 것과 혼합되지 않음) 계층의 일부입니다. 코드 내부에 잘못 배치되었을 수 있습니다. 이 메소드는 별도의 클래스 인 "데이터베이스 인터페이스 계층"에 속합니다. 비 데이터베이스 활동을 구현하는 메소드 옆의 일반 클래스 내에 배치하는 것은 안티 패턴입니다.

안티 패턴은 다른 임의의 코드 위치에서 SQL을 호출하는 것입니다. 데이터베이스와 나머지 코드 사이에 계층을 정의해야하지만 거기에서 도움을 줄 수있는 널리 사용되는 도구를 반드시 사용해야하는 것은 아닙니다.


0

제 생각 에는 안티 패턴하지 않습니다하지만 당신은 자신이 특히 한 줄에 들어갈 수없는 큰 쿼리 문자열의 서식 공간을 다루는 찾을 수 있습니다.

또 다른 장점은 특정 조건에 따라 작성해야하는 동적 쿼리를 처리 할 때 훨씬 어려워진다는 것입니다.

var query = "select * from accounts";

if(users.IsInRole('admin'))
{
   query += " join secret_balances";
}

SQL 쿼리 빌더를 사용하는 것이 좋습니다.


속기를 사용하는 것일 수도 있지만 필요하지 않은 필드 (대역폭 !!)를 다시 가져 오기 때문에 "SELECT *"를 맹목적으로 사용하는 것은 좋지 않습니다. 조건부 Admin 절에 문제가 없지만 조건부 "WHERE"절로 매우 미끄러운 경사면을 내려 가며 성능 저하로 바로 이어지는 길입니다.
mcottle

0

코드 배포를 몇 분 안에 컴파일, 테스트 및 프로덕션으로 푸시 할 수있는 빠른 배포 파이프 라인이있는 많은 현대 조직의 경우 SQL 문을 응용 프로그램 코드에 포함시키는 것이 좋습니다. 이것이 어떻게 진행되는지에 따라 반 패턴이 될 필요는 없습니다.

오늘날 저장 프로 시저를 사용하는 데 유효한 사례는 몇 주 간의 QA주기 등을 포함 할 수있는 프로덕션 배포와 관련된 많은 프로세스가있는 조직에서 발생합니다.이 시나리오에서 DBA 팀은 초기 프로덕션 배포 후에 만 ​​발생하는 성능 문제를 최적화하여 해결할 수 있습니다. 저장 프로 시저의 쿼리

이 상황에 있지 않으면 SQL을 응용 프로그램 코드에 포함시키는 것이 좋습니다. 이 스레드의 다른 답변을 읽고 최선의 방법에 대한 조언을 얻으십시오.


상황에 맞는 아래의 원본

저장 프로 시저의 주요 장점은 응용 프로그램을 다시 컴파일하고 재배포하지 않고도 데이터베이스 성능을 최적화 할 수 있다는 것입니다.

많은 조직에서 코드는 며칠 또는 몇 주가 소요될 수있는 QA주기 후에 만 ​​프로덕션으로 푸시 될 수 있습니다. 사용 패턴 변경이나 테이블 크기 증가 등으로 인해 시스템에서 데이터베이스 성능 문제가 발생하는 경우 하드 코딩 된 쿼리로 문제를 추적하는 것이 매우 어려울 수 있지만 데이터베이스에는 문제 저장 프로 시저를 식별하는 도구 / 보고서가 있습니다. . 저장 프로 시저를 사용하면 프로덕션 환경에서 솔루션을 테스트 / 벤치 할 수 있으며 새로운 버전의 응용 프로그램 소프트웨어를 푸시하지 않고도 문제를 신속하게 해결할 수 있습니다.

이 문제가 시스템에서 중요하지 않은 경우 SQL 문을 응용 프로그램에 하드 코딩하는 것이 완벽하게 결정됩니다.


잘못 ..............
Sentinel

귀하의 의견이 다른 사람에게 도움이된다고 생각하십니까?
bikeman868

이것은 단지 틀린 것입니다. EF를 데이터 액세스로, Azure Sql을 저장소로 사용하는 Web API2 프로젝트가 있다고 가정하겠습니다. DB 스키마는 SSDT SQL Server 프로젝트에 저장됩니다 .DB 스키마 마이그레이션은 코드베이스를 db 스키마에 동기화하고 테스트를 진행하기 전에 완전히 테스트해야합니다. 코드 변경에는 2 초가 걸리는 App Service 배포 슬롯으로 푸시하는 작업이 포함됩니다. 또한 수작업으로 작성된 SQL은 반대로 '지혜'에도 불구하고 저장 프로 시저에 비해 성능이 향상됩니다.
Sentinel

귀하의 경우 배포에 몇 초가 걸릴 수 있지만 많은 사람들에게는 그렇지 않습니다. 나는 저장 프로 시저가 더 좋다고 말하지 않았으며, 어떤 상황에서는 몇 가지 장점이 있습니다. 마지막 진술은 이러한 상황이 적용되지 않으면 SQL을 응용 프로그램에 넣는 것이 매우 유효하다는 것입니다. 이것은 당신이 말하는 것과 어떻게 모순됩니까?
bikeman868

저장 프로시 저는 수작업으로 만들어진 SQL ???
bikeman868
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.