가장 일반적인 SQL 안티 패턴은 무엇입니까? [닫은]


232

관계형 데이터베이스를 다루는 우리 모두는 SQL이 다르다는 것을 배웠습니다. 원하는 결과를 도출하고 효율적으로 수행하려면 익숙하지 않은 패러다임을 배우고 가장 친숙한 프로그래밍 패턴 중 일부가 여기서 작동하지 않는 것을 발견하는 지루한 프로세스가 필요합니다. 당신이 본 (또는 당신이 저지른) 일반적인 반 패턴은 무엇입니까?


이것은 어떤 유형의 질문이 스택 오버플로에 적합한 지에 대한 새로운 표준을 따르지 않는 질문입니다. 요청을 받았을 때, 이것은 사실이 아닐 수도 있습니다.
David Manheim

@casperOne이 질문을 받아 들일만한 "역사적 중요성"조항이 없습니까?
Amy B

26
나는 전체 사이트에서 가장 유용한 질문 중 하나가 건설적이지 않은 것으로 닫혀서 안타깝습니다.
HLGEM

11
@HLGEM 전적으로 동의합니다. 이 질문은 StackExchange에서 잘못된 모든 것의 완벽한 예입니다.
Kevin Morse

1
주제는 절대적으로 중요하고 관련이 있습니다. 그러나이 질문은 너무 개방적이므로 답변은 개별 엔지니어의 개인 안티 패턴 버그 베어를 각각 설명하는 이유입니다.
Shane

답변:


156

데이터 액세스 계층에서 UI 논리를 혼합하려는 대부분의 프로그래머 경향에 대해 일관되게 실망합니다.

SELECT
    FirstName + ' ' + LastName as "Full Name",
    case UserRole
        when 2 then "Admin"
        when 1 then "Moderator"
        else "User"
    end as "User's Role",
    case SignedIn
        when 0 then "Logged in"
        else "Logged out"
    end as "User signed in?",
    Convert(varchar(100), LastSignOn, 101) as "Last Sign On",
    DateDiff('d', LastSignOn, getDate()) as "Days since last sign on",
    AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' +
        City + ', ' + State + ' ' + Zip as "Address",
    'XXX-XX-' + Substring(
        Convert(varchar(9), SSN), 6, 4) as "Social Security #"
FROM Users

일반적으로 프로그래머는 데이터 집합을 그리드에 직접 바인딩하려고하기 때문에 클라이언트에서 형식보다 SQL Server 형식의 서버 쪽을 사용하는 것이 편리하기 때문에이 작업을 수행합니다.

위에 표시된 것과 같은 쿼리는 데이터 계층을 UI 계층에 밀접하게 연결하기 때문에 매우 취약합니다. 또한이 프로그래밍 스타일은 저장 프로 시저를 재사용 할 수 없도록 철저히 방지합니다.


10
가능한 최대 수의 계층 / 추상화 계층에서 최대 결합을위한 좋은 포스터-자식 패턴입니다.
dkretz

3
디커플링에는 좋지 않을 수도 있지만 성능상의 이유로 SQL Server에서 수행하는 반복적 인 변경은 중간 계층의 코드보다 훨씬 빠릅니다. 나는 당신에게 재사용 포인트를 얻지 못합니다. 원하는 경우 SP를 실행하고 열 이름을 바꾸는 것을 막을 수있는 것은 없습니다.
Joe Pineda

54
내가 좋아하는 것은 사람들이 HTML과 자바 스크립트를 포함 할 때입니다. 예 : SELECT '<a href=... onclick="">'+ name '</a>'
Matt Rogish

15
이와 같은 쿼리를 사용하면 간단한 alter 문을 사용하여 웹 사이트에서 그리드를 편집 할 수 있습니다. 또는 내보내기 내용을 변경하거나 보고서에서 날짜를 다시 포맷하십시오. 이것은 고객을 행복하게 만들고 시간을 절약 해줍니다. 고마워,하지만 고마워, 나는 이런 쿼리를 고수 할 것이다.
Andomar

4
@ 매트 Rogish-예수, 누군가가 실제로 그렇게합니까?
Axarydax

118

여기 내 탑 3이 있습니다.

번호 1. 필드 목록을 지정하지 못했습니다. (편집 : 혼란을 피하기 위해 : 이것은 프로덕션 코드 규칙입니다. 저자가 아닌 한 일회성 분석 스크립트에는 적용되지 않습니다.)

SELECT *
Insert Into blah SELECT *

해야한다

SELECT fieldlist
Insert Into blah (fieldlist) SELECT fieldlist

루프 변수가있는 while 루프가 수행 될 때 커서와 while 루프를 사용합니다.

DECLARE @LoopVar int

SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable)
WHILE @LoopVar is not null
BEGIN
  -- Do Stuff with current value of @LoopVar
  ...
  --Ok, done, now get the next value
  SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable
    WHERE @LoopVar < TheKey)
END

문자열 유형을 통한 DateLogic

--Trim the time
Convert(Convert(theDate, varchar(10), 121), datetime)

해야한다

--Trim the time
DateAdd(dd, DateDiff(dd, 0, theDate), 0)

최근에 "하나의 쿼리가 두 개보다 낫습니다."라는 급증을 보았습니다.

SELECT *
FROM blah
WHERE (blah.Name = @name OR @name is null)
  AND (blah.Purpose = @Purpose OR @Purpose is null)

이 쿼리에는 매개 변수 값에 따라 두 개 또는 세 개의 다른 실행 계획이 필요합니다. 이 SQL 텍스트에 대해 하나의 실행 계획 만 생성되어 캐시에 고정됩니다. 이 계획은 매개 변수 값에 관계없이 사용됩니다. 결과적으로 간헐적으로 성능이 저하됩니다. 의도 한 실행 계획 당 하나의 쿼리 인 두 개의 쿼리를 작성하는 것이 훨씬 좋습니다.


7
흠, 2 점과 3 점에 대해서만 +1을 주지만 개발자는 규칙 1을 능가합니다. 때로는 장소가 있습니다.
annakata

1
# 1의 이유는 무엇입니까?
jalf December

29
select *를 사용하면 테이블에있는 모든 것을 얻습니다. 해당 열은 이름과 순서가 변경 될 수 있습니다. 클라이언트 코드는 종종 이름과 순서에 의존합니다. 6 개월마다 테이블을 수정할 때 열 순서를 유지하는 방법을 묻습니다. 규칙을 준수하면 문제가되지 않습니다.
Amy B

때로는 # 2를 사용하고 다른 사람들은 커서 경로를갔습니다 (그러나 먼저 쿼리 결과를 테이블 var에 저장하고 커서를 엽니 다). 나는 누군가가 둘 다의 성능 테스트를 수행했는지 항상 궁금했습니다.
Joe Pineda

4
... 물론 세트 기반 SQL로 작업을 수행하는 방법을 찾지 못하면 커서는 항상 최후의 수단이어야합니다. 나는 한 번 45 분 동안 저장 프로 시저에서 끔찍하고 거대한 PL / SQL 커서를 조심스럽게 해부했습니다 (썩은 것의 다이어그램을 그렸습니다). 보고서. 상당한 하드웨어에서 실행하는 데 8.5 분이 걸렸습니다. 모든 것을 다이어그램으로 만든 후 2 초 안에 동일한 결과를 반환하는 단일 쿼리로 대체 할 수있었습니다. 커서, 남자 ...
Craig Craig

71
  • 사람이 읽을 수있는 비밀번호 필드 (예 : ad) 자기 설명.

  • 인덱스 열에 대해 LIKE를 사용하면 일반적으로 LIKE라고 말하고 싶어합니다.

  • SQL 생성 PK 값을 재활용합니다.

  • 서프라이즈 아무도 언급하지 신 테이블을 아직. 100 열의 비트 플래그, 큰 문자열 및 정수와 같은 "유기적"이란 말은 없습니다.

  • 그런 다음 CSV 파일 , 파이프로 구분 된 문자열 또는 기타 구문 분석이 필요한 데이터를 큰 텍스트 필드에 저장하는 ".ini 파일이 누락되었습니다" 패턴이 있습니다.

  • 그리고 MS SQL 서버의 경우 커서 를 전혀 사용하지 않습니다 . 주어진 커서 작업을 수행하는 더 좋은 방법이 있습니다.

너무 많아 편집했습니다!


19
커서에 대해 틀렸다면, 특정 일을하는 것이 100 % 옳거나 100 % 잘못되었다고 말하는 것이 주저 할 것입니다
Shawn

4
지금까지 내가 본 모든 커서 방어 예제는 작업에 잘못된 도구를 사용하는 것입니다. 그러나 SQL 만 알고 있다면 SQL을 부적절하게 사용하거나 다른 종류의 소프트웨어 작성법을 배우게됩니다.
dkretz

3
@ tuinstoel : LIKE '% blah %'는 어떻게 인덱스를 사용합니까? 인덱싱은 순서에 의존하며이 예제는 문자열의 임의의 중간 위치를 검색합니다. (인덱스가 ... 1 문자 1 일까지 주문, 그래서 중간 4 자보고하는 것은 사실상 임의의 순서를 제공합니다)
MatBailie

12
대부분의 데이터베이스 서버 (적어도 내가 사용한 서버)에서 LIKE는 접두어 검색 (LIKE 'xxx %') 인 한, 즉 와일드 카드 문자가 아닌 한 인덱스를 사용할 수 있습니다. 검색 문자열에서 맨 먼저옵니다. 나는 당신이 여기에서 목적에 대해 조금 이야기하고 있다고 생각합니다.
Cowan

10
당신이 싫어하는 것 같습니다 LIKE '%LIKE'.
Johan

62

깊이 파고들 필요가 없습니다. 준비된 진술을 사용하지 마십시오.


3
예. 내 경험상, "트 랩핑 오류가 없음"과 같은 맥락에서 면밀히 따랐다.
dkretz

1
@stesch : 조회수를 사용하고보고 날짜를 가변적으로 사용하는 것과 비교하면 아무것도 아닙니다. 가변보고 날짜가있는 경우보기는 반 패턴입니다 (대부분의 응용 프로그램에 있다고 가정). 이것을 별도의 답변으로 추가 할 수는 있지만 불행히도 닫힙니다.
Stefan Steiger

56

무의미한 테이블 별칭 사용 :

from employee t1,
department t2,
job t3,
...

큰 SQL 문을 읽는 것보다 훨씬 어렵게 만듭니다.


49
별명? 지옥 같은 실제 열 이름을 보았다
annakata

10
간결한 별칭은 OKAY입니다. 의미있는 이름을 원한다면 별명을 사용하지 마십시오.
Joel Coehoorn

43
그는 "더 이상하지 않다"고 말하지 않았다. 필자의 책에는 예제 쿼리에서 별명으로 e, d 및 j를 사용하는 데 아무런 문제가 없습니다.
Robert Rossney

11
물론 Robert-e, d, j는 괜찮을 것입니다.
Tony Andrews

8
나는 직원에 대한 EMP, 출발 작업 부서 및 작업 (또는 어쩌면 JB) : 사용합니다
안드레이 Rînea

53
var query = "select COUNT(*) from Users where UserName = '" 
            + tbUser.Text 
            + "' and Password = '" 
            + tbPassword.Text +"'";
  1. 맹목적으로 신뢰하는 사용자 입력
  2. 매개 변수화 된 쿼리를 사용하지 않음
  3. 일반 텍스트 비밀번호

이들 모두는 어떤 종류의 데이터베이스 추상 계층을 사용하여 유용하게 처리 할 수 ​​있습니다.
dkretz

@doofledorfer : 동의합니다. 중간 계층이 이와 같은 경우에 더 좋을 것이며 결과를 캐싱하여 멋진 부작용으로 제공 할 것입니다.
Joe Pineda

멋진 예입니다. 개발자가이를 좋은 솔루션으로 대체하는 방법을 모색하면 적절한 SQL 개발자가되기위한 반쯤입니다.
Steve McLeod

46

내 버그 베어는 450 명의 열 액세스 테이블로, 상무 이사의 가장 친한 친구 개 그 루머의 8 살짜리 아들과 누군가가 데이터 구조를 올바르게 정규화하는 방법을 모르기 때문에 존재하는 닷지 조회 테이블입니다.

일반적으로이 조회 테이블은 다음과 같습니다.

ID INT,
NVARCHAR (132) 이름,
IntValue1 INT,
IntValue2 INT,
CharValue1 NVARCHAR (255),
CharValue2 NVARCHAR (255),
날짜 1 DATETIME,
날짜 2 DATETIME

나는 이와 같은 가증에 의존하는 시스템을 가지고있는 고객을 보았습니다.


1
설상가상으로, 나는 것이다 두려워 실제로 자동 지원의 액세스의 최신의 버전을 읽고 격려 더이 값 1, 값, VALUE3 ... 열 fetichism의
조 피네다

잠깐-8 살짜리 아들이 개 손질의 아들입니까?
barrypicker

28

내가 가장 싫어하는 것은

  1. CamelCase 또는 under_scores 및 단수 또는 복수형 및 대문자 또는 소문자는 괜찮지 만 특히 [이상하게 간격이있는 경우] (예, 공백이있는 경우) 테이블 또는 열을 참조해야합니다 (예, 나는 이것에 부딪쳤다) 정말로 나를 자극한다.

  2. 비정규 화 된 데이터. 테이블을 완벽하게 정규화 할 필요는 없지만 현재 평가 점수 또는 주요 내용에 대한 정보가있는 직원 테이블에 들어가면 특정 시점에서 별도의 테이블을 만들어야 할 것입니다. 그런 다음 동기화 상태를 유지하십시오. 먼저 데이터를 정규화 한 다음 비정규 화가 도움이되는 곳을 찾으면 고려하겠습니다.

  3. 뷰 또는 커서를 과도하게 사용합니다. 뷰에는 목적이 있지만 각 테이블이 뷰에 래핑되면 너무 많습니다. 커서를 몇 번 사용해야했지만 일반적으로 다른 메커니즘을 사용할 수 있습니다.

  4. 접속하다. 프로그램이 반 패턴 일 수 있습니까? 우리 회사에는 SQL Server가 있지만 기술이 아닌 사용자에게는 "사용 편의성"및 "친 화성"이라는 가용성으로 인해 많은 사람들이 액세스를 사용합니다. 여기에 너무 많은 것이 있지만 비슷한 환경에 있었다면 알 것입니다.


2
# 4-<a href=' stackoverflow.com/questions/327199/…> :)에 대한 또 다른 스레드가 있습니다 .
dkretz

4
액세스는 DBMS가 아닙니다. 매우 간단한 데이터베이스 관리자가 포함 된 RAD 환경입니다. SQL Server, Oracle 등 것입니다 결코 당신이 언어와 시설 같은 크리스탈 리포트와 같은 VB-A를 추가하지 않는 한, 그것을 대체하지 않습니다.
Joe Pineda

26

저장 프로 시저 이름의 접두사로 SP를 사용하십시오. 먼저 사용자 지정 위치가 아닌 시스템 프로 시저 위치에서 검색하기 때문입니다.


1
또한 모든 저장 프로 시저에 다른 공통 접두사를 사용하도록 확장 할 수 있으므로 정렬 된 목록을 선택하기가 더 어려워집니다.
dkretz

7
doofledorfer의 댓글 +1 나는 이것을 많이 보았고, 나는이 바보를 발견하고 실제로 특정 SP를 검색하는 것을 매우 어렵게 만듭니다! 또한 뷰의 경우 "vw_", 테이블의 경우 "tbl_"등으로 확장됩니다.
Joe Pineda

1
접두사는 개체를 파일로 스크립팅 할 때 유용 할 수 있습니다 (예 : 소스 제어, 배포 또는 마이그레이션)
Rick

1
지구상에서 모든 단일 저장 프로 시저에 sp 또는 usp 를 접두어로 붙이는 것이 왜 유용한가 ? 원하는 목록을 검색하기가 더 어려워집니다.
Ryan Lundy

25

임시 테이블 및 커서의 남용.


2
"내가 아는 전부는 절차 적 언어"라는 좋은 증거.
dkretz

2
무엇인가의 남용은 정의상 원치 않는 것입니다. 임시 테이블 / 커서를 사용하지 않아도되는 구체적인 예가 도움이 될 것입니다.
Jace Rhea

6
주로 임시 테이블의 사용량이 적습니다. SQL Server를 사용하면 하나의 모 놀리 식 쿼리 대신 여러 임시 테이블로 작업을 수행하여 성능을 향상시킬 수 있습니다.
Cervo

24

시간 값을 저장하려면 UTC 시간대 만 사용해야합니다. 현지 시간을 사용해서는 안됩니다.


3
나는 여전히 일광 절약 시간을 고려해야 할 때 과거의 날짜에 대해 UTC에서 현지 시간으로 변환하는 좋은 간단한 해결책을 찾지 못했습니다. 여러 국가 및 국가에 따라 다양한 변경 날짜뿐만 아니라 국가 내의 모든 예외가 있습니다. 따라서 UTC는 변환 복잡성을 피할 수 없습니다. 그러나 저장된 모든 날짜 시간의 시간대를 알 수있는 방법이 중요합니다.
ckarras

1
@CsongorHalmai 많은 곳에서 일광 절약 시간제를 사용하므로 시간 이동 후 1 시간 이내의 시간 값이 모호 할 수 있습니다.
Frank Schwieterman

그것은 현재와 과거에는 확실히 맞지만 미래, 특히 상당히 먼 미래에는 명시적인 시간대가 종종 필요합니다. 뉴욕 시간으로 2049-09-27T17 : 00 : 00에 작성되어 만료 된 30 년 옵션이 있다면 맹목적으로 21 : 00 : 00Z라고 가정 할 수 없습니다. 미국 의회는 DST 규칙을 변경할 수 있습니다. 현지 시간과 실제 시간대 (America / New_York)를 별도로 유지해야합니다.
John Cowan

23

SCOPE_IDENTITY () 대신 @@ IDENTITY 사용

이 답변 에서 인용 :

  • @@ IDENTITY 는 모든 세션에서 현재 세션의 테이블에 대해 생성 된 마지막 ID 값을 반환합니다. 범위가 다르므로 여기서주의해야합니다. 현재 명령문 대신 트리거에서 값을 얻을 수 있습니다.
  • SCOPE_IDENTITY 는 현재 세션 및 현재 범위의 테이블에 대해 생성 된 마지막 ID 값을 반환합니다. 일반적으로 사용하고 싶은 것.
  • IDENT_CURRENT 는 모든 세션 및 범위에서 특정 테이블에 대해 생성 된 마지막 ID 값을 반환합니다. 이를 통해 위의 두 가지가 필요한 것이 아닌 경우 (매우 드물게) 값을 원하는 테이블을 지정할 수 있습니다. 레코드를 삽입하지 않은 테이블의 현재 IDENTITY 값을 가져 오려는 경우이를 사용할 수 있습니다.

+1 매우 사실,
잡기

23

의도하지 않은 용도로 '죽은'필드를 재사용 (예 : '팩스'필드에 사용자 데이터 저장) – 빠른 수정으로 매우 유혹적입니다!


21
select some_column, ...
from some_table
group by some_column

결과가 some_column으로 정렬된다고 가정합니다. Sybase에서 가정이 유지되는 현재 부분을 보았습니다.


1
정렬 순서를 가정하는 모든 사람들을위한 찬성 투표는 쿼리 도구에서 한 번만 나타난 방식 이었기 때문에
Joel Coehoorn

3
나는 이것을 두 번 이상 버그로보고했습니다.
dkretz

6
MySQL에서는 정렬이 문서화되어 있습니다. < dev.mysql.com/doc/refman/5.0/en/select.html >. 따라서 MySQL을 다시 비난하십시오.
derobert

1
Oracle에서는 정렬되지 않은 결과 (거의)가 버전 10G까지 항상 그룹화와 일치했습니다. ORDER BY를 사용하지 않은 개발자들을위한 많은 재 작업!
Tony Andrews

1
나는 이것이 SQL Server에 대한 사실로 언급 된 훈련 수업에도있었습니다. 나는 정말로 큰 소리로 항의해야했다. 20 자만 입력하면 저장되지 않거나 문서화되지 않은 동작이 사용됩니다.
erikkallen 2009

20
SELECT FirstName + ' ' + LastName as "Full Name", case UserRole when 2 then "Admin" when 1 then "Moderator" else "User" end as "User's Role", case SignedIn when 0 then "Logged in" else "Logged out" end as "User signed in?", Convert(varchar(100), LastSignOn, 101) as "Last Sign On", DateDiff('d', LastSignOn, getDate()) as "Days since last sign on", AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' + City + ', ' + State + ' ' + Zip as "Address", 'XXX-XX-' + Substring(Convert(varchar(9), SSN), 6, 4) as "Social Security #" FROM Users

또는 모든 것을 한 줄에 넣습니다.


이전 주석의 쿼리를 사용했습니다. 이것이 사용 가능한 첫 번째 SQL 문이기 때문입니다.
Jasper Bekkers

17
  • FROM TableA, TableB WHERE에 대한 구문보다는 JOINSFROM TableA INNER JOIN TableB ON

  • 쿼리가 반환 될 것이라고 가정하면 쿼리 도구에서 테스트하는 동안 ORDER BY 절을 넣지 않고 특정 방식으로 정렬됩니다.


5
Oracle DBA는 항상 "ANSI 조인", 즉 올바른 방식으로 제공하는 것을 사용한다고 불평합니다. 그러나 나는 그것을 계속하고 있으며, 그들이 깊이 알고 있다고 생각합니다.
Steve McLeod

1
오라클은 표준 SQL이 사라지기를 바라고 있습니다. :-) 또한 MySQL 5에서 암시 적 및 명시 적 JOINS (일명 ANSI JOIN)를 혼합 할 수 없습니다. 작동하지 않습니다. 명시 적 JION에 대한 또 다른 논쟁입니다.
staticsan

3
A INNER JOIN B ON조차도 반 패턴입니다. 나는 A INNER JOIN B 사용을 선호합니다.
John Nilsson

오라클은 현재 ANSI 구문을 지원하지만 과거에는 외부 조인에 대해이 이상한 구문을 사용했으며 여전히 너무 많은 사람들이 사용하고 있습니다.
Cervo

음 ... 오라클은 여전히 ANSI가 조인 사용하지 않습니다 에 커밋 구체화 된 뷰, 빠른 새로 고칠 수
Gerrat을

14

경력의 첫 6 개월 동안 SQL을 배우고 향후 10 년 동안 다른 것을 배우지 마십시오. 특히 창 / 분석 SQL 기능을 배우거나 효과적으로 사용하지 않습니다. 특히 over () 및 by by를 사용합니다.

집계 함수와 같은 창 함수는 정의 된 행 집합 (그룹)에 대해 집계를 수행하지만 그룹당 하나의 값을 반환하는 대신 창 함수는 각 그룹에 대해 여러 값을 반환 할 수 있습니다.

윈도우 기능에 대한 훌륭한 개요는 O'Reilly SQL Cookbook 부록 A 를 참조하십시오 .


12

나는 목록을 완성하기 위해 현재 자신이 좋아하는 것을 여기에 넣어야합니다. 내가 가장 좋아하는 반 패턴은 쿼리를 테스트하지 않습니다 .

다음과 같은 경우에 적용됩니다.

  1. 쿼리에 둘 이상의 테이블이 포함됩니다.
  2. 쿼리에 대한 최적의 디자인이 있다고 생각하지만 가정을 테스트하지 않아도됩니다.
  3. 최적화 된 쿼리에 가까운 지에 대한 단서없이 작동하는 첫 번째 쿼리를 수락합니다.

그리고 비정형 또는 불충분 한 데이터에 대해 실행되는 테스트는 포함되지 않습니다. 저장 프로 시저 인 경우 테스트 문을 주석에 넣고 결과와 함께 저장하십시오. 그렇지 않으면 결과와 함께 코드에 주석을 추가하십시오.


최소한의 T-SQL 테스트에 매우 유용한 기술 : SP, UDF 등을 정의하는 .SQL 파일에서 IF 1 = 2 BEGIN (예제 결과와 함께 코드의 샘플 사례)과 같은 블록 테스트를 생성 한 직후 END
Joe Pineda 2018

SQL Server는 코드가 실행되지 않더라도 테스트 블록 내에서 코드를 구문 분석합니다. 따라서 객체가 수정되어 더 많은 매개 변수 또는 다른 유형 등을 받거나 객체가 의존하는 객체가 수정되면 실행 계획을 요청하는 것만으로 오류가 발생합니다!
Joe Pineda

실제 데이터로 테스트하는 것이 항상 가능한 것은 아닙니다. 종종 dev 서버 / "테스트"서버는 유료이며 실제 서버의 일부를받습니다. 일반적으로 테스트는 라이브 서버에 대해 찌그러집니다. 일부 장소가 더 좋으며 라이브 데이터가있는 테스트 또는 스테이징 서버가 있습니다.
Cervo

11

임시 테이블 남용.

구체적으로 이런 종류의 것 :

SELECT personid, firstname, lastname, age
INTO #tmpPeople
FROM People
WHERE lastname like 's%'

DELETE FROM #tmpPeople
WHERE firstname = 'John'

DELETE FROM #tmpPeople
WHERE firstname = 'Jon'

DELETE FROM #tmpPeople
WHERE age > 35

UPDATE People
SET firstname = 'Fred'
WHERE personid IN (SELECT personid from #tmpPeople)

쿼리에서 임시 테이블을 작성하지 말고 필요없는 행만 삭제하십시오.

그리고 예, 프로덕션 DB 에서이 형식의 코드 페이지를 보았습니다.


1
+1, 동의합니다. 비록이 기술이 성능을 향상시키는 적어도 하나 또는 두 가지 경우를 발견했지만 관련 쿼리는 가장 복잡합니다.
a'r

1
사실 - 그들은 그냥 모든 쿼리 :)에, 장소가 할
geofftnz

1
때로는 조건이 매우 복잡한 경우에는 그렇게해야합니다. 사실 그것은 극단적으로 남용 될 수 있습니다. 그러나 여러 번의 간단한 삭제는 초기 쿼리에서 사례를 얻는 논리보다 훨씬 간단합니다. 또한 절을 sargeable 할 수없는 경우 초기 쿼리 속도가 느려집니다. 그러나 더 작은 임시 테이블에서 수행하는 것이 더 효율적입니다. 그리고 다른 경우에는 비즈니스 사람들이 사실을 계속해서 추가하는 사례를 계속 추가합니다.
Cervo

9

반대 론적 견해 : 정규화에 대한 집착.

대부분의 SQL / RBDB 시스템은 정규화되지 않은 데이터에서도 매우 유용한 기능 (트랜잭션, 복제)을 제공합니다. 디스크 공간이 저렴하고 1NF 스키마를 작성하는 것보다 페치 된 데이터를 조작 / 필터링 / 검색하는 것이 더 간단하고 (더 쉬운 코드, 개발 시간이 더 빠름), 모든 복잡한 문제 (복잡한 조인, 불쾌한 하위 선택)를 처리 할 수 ​​있습니다. 등).

과도 표준화 된 시스템은 특히 조기 개발 단계에서 조기에 최적화되는 경우가 많습니다.

(더 많은 생각은 ... http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/ )


22
비정규 화는 종종 조기 최적화라고 생각합니다.
tuinstoel

때때로, 때로는 그렇지 않습니다. 운 좋게도 종종 테스트하기가 쉽고 다른 옵션이 다른 db 요구에 작동합니다.
Gregg Lind

17
정규화는 디스크 공간 절약만을위한 것이 아닙니다. 또한 데이터에 대한 권한있는 소스를 작성해야합니다. 데이터가 한 곳에만 저장되는 경우 일관성은 신중한 코딩의 부산물이 아니라 디자인의 부산물입니다.
Grant Johnson

복합 형식의 데이터를 JSON 형식으로 저장하는 것이 한 가지입니다. 점점 더 많은 지원이 있으며 이는 의식적인 트레이드 오프입니다. 하나의 조인을 저장하기 위해 쉼표로 구분 된 (또는 다른 값) 값을 사용하는 것은 페니와 현명한 어리석은 일입니다.
John Cowan

noSQL 솔루션은 다중 테이블 조회를 제거함으로써 중복 데이터 비용으로 성능 이점을 보여줍니다. 전체 정규화를 머리에 넣습니다. 일부 예들에서, 하나의 프로세스가 가능한 가장 빠른 응답 시간을 갖도록 데이터가 여러 장소에서 수집된다. 물론 권위있는 출처에 관한 질문이옵니다.
barrypicker

9

SO에 대한 SQL 응답 중 일부를 기반 으로이 것을 하나로 묶었습니다.

이벤트 핸들러가 OOP에 따라 트리거가 데이터베이스에 있다고 생각하는 것은 심각한 반 패턴입니다. 트랜잭션 (이벤트)이 테이블에서 발생할 때 발생하는 오래된 로직 만 트리거에 넣을 수 있다는 인식이 있습니다.

사실이 아니다. 가장 큰 차이점 중 하나는 트리거가 행 작업이 아니라 세트 작업에서 동기식이기 때문에 트리거가 복수라는 점입니다. OOP 측면에서 정확히 반대의 이벤트는 비동기 트랜잭션을 구현하는 효율적인 방법입니다.


8

주석이없는 저장 프로 시저 또는 함수 ...


그리고 뷰;) 테이블 반환 함수 (= 매개 변수가있는 뷰)를 제외하고 함수는 true입니다.
Stefan Steiger

7

1) 이것이 "공식적인"반 패턴인지는 모르지만, 데이터베이스 열에서 문자열 리터럴을 마술 값으로 사용하는 것을 싫어합니다.

MediaWiki의 테이블 'image'의 예 :

img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", 
    "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
img_major_mime ENUM("unknown", "application", "audio", "image", "text", 
    "video", "message", "model", "multipart") NOT NULL default "unknown",

(방금 다른 케이싱, 피해야 할 또 다른 것을 알았습니다)

int 기본 키를 사용하여 ImageMediaType 및 ImageMajorMime 테이블에 대한 int 조회와 같은 사례를 디자인합니다.

2) 특정 NLS 설정에 의존하는 날짜 / 문자열 변환

CONVERT(NVARCHAR, GETDATE())

형식 식별자없이


구문적인 들여 쓰기도 없습니다. 아가
dkretz

2
왜 이것이 나쁜가요? 반드시 일련의 값을 표현하려고하면 조회 테이블뿐만 아니라 작동하며이를 호출하는 코드에 더 적합합니다. ID는 내 앱 코드에 조회 테이블의 특정 행에 매핑되는 앱 코드의 열거보다 내 DB의 열거 제약 조건에 매핑되는 열거 형이 있습니다. 더 깨끗해집니다.
잭 라이언

@ JackRyan : 나중에 열거 목록을 변경할 때 두 위치에서 변경해야한다는 것을 기억해야하기 때문에 이것은 나쁩니다. DRY를 위반 합니다. 데이터베이스는 진실의 단일 소스 여야합니다.
Gerrat

7

쿼리에서 동일한 하위 쿼리


10
불행히도 때로는 피할 수 없습니다-SQL 2000에는 "WITH"키워드가 없었으며 UDF를 사용하여 일반적인 하위 쿼리를 캡슐화하여 성능 저하를 초래할 수 있습니다. MS를 비난하십시오.
Joe Pineda

글쎄, 그들은 요즘 하나를 추가 할 것입니다.
EvilTeach

SQL 2000에서는 테이블 변수를 사용할 수 있습니다.
재귀

@ 재귀 : 테이블 변수에 인덱스를 가질 수 없으므로 하위 쿼리보다 느리게 만듭니다. 그러나 사용자 정의 인덱스와 함께 임시 테이블을 사용할 수 있습니다.
Rick

Cool은 수년간 SQL로 작업 해 왔으며 공통 테이블 표현식이 존재하는지도 몰랐습니다 (필요한 경우도 있음). 이제 해! 감사!
sleske

7
  • Altered View (변경된보기)-너무 자주 변경되고 예고 나 이유없이 변경되는보기. 변경은 가장 부적절한 시간에 통지되거나 더 잘못되어 통지되지 않습니다. 누군가가 해당 열의 더 나은 이름을 생각했기 때문에 응용 프로그램이 중단 될 수 있습니다. 규칙 뷰는 기본 테이블의 유용성을 확장하면서 소비자와의 계약을 유지해야합니다. 새로운보기를 만들기 위해 문제를 해결하지만 기능을 추가하거나 변경 동작을 악화시키지 마십시오. 완화하려면 다른 프로젝트와 뷰를 공유하지 않고 플랫폼이 허용 하는 경우 CTE 를 사용하십시오. 상점에 DBA가있는 경우보기를 변경할 수 없지만 모든보기가 오래되거나 쓸모가 없습니다.

  • ! Paramed-쿼리에 둘 이상의 목적이있을 수 있습니까? 아마 다음에 읽는 사람은 깊은 명상을하기 전까지는 알 수 없을 것입니다. 지금 당장 필요하지 않더라도 디버그하는 것이 "단지"라도 가능할 것입니다. 매개 변수를 추가하면 유지 보수 시간이 줄어들고 건조 상태가 유지됩니다. where 절이 있으면 매개 변수가 있어야합니다.

  • CASE가없는 경우-

    SELECT  
    CASE @problem  
      WHEN 'Need to replace column A with this medium to large collection of strings hanging out in my code.'  
        THEN 'Create a table for lookup and add to your from clause.'  
      WHEN 'Scrubbing values in the result set based on some business rules.'  
        THEN 'Fix the data in the database'  
      WHEN 'Formating dates or numbers.'   
        THEN 'Apply formating in the presentation layer.'  
      WHEN 'Createing a cross tab'  
        THEN 'Good, but in reporting you should probably be using cross tab, matrix or pivot templates'   
    ELSE 'You probably found another case for no CASE but now I have to edit my code instead of enriching the data...' END  

그 세 번째를 좋아했습니다. 나는 이미 ... 로컬로 사용하고 있습니다
alphadogg

소품 주셔서 감사합니다. :)
Jason saldo

5

가장 많이 찾은 두 가지 성능 측면에서 상당한 비용이 발생할 수 있습니다.

  • 세트 기반 표현식 대신 커서 사용. 나는 이것이 프로그래머가 절차 적으로 생각할 때 자주 발생한다고 생각합니다.

  • 파생 테이블에 대한 조인이 작업을 수행 할 수있는 경우 상관 된 하위 쿼리를 사용합니다.


내가 생각하는 바를 의미한다면 동의합니다. 상관 서브 쿼리는 파생 테이블 IIRC의 유형이지만.
dkretz

1
파생 된 테이블은 설정 작업이지만 외부 쿼리의 각 행에 대해 상관 된 하위 쿼리가 실행되므로 효율성이 떨어집니다 (10 중 9 회)
Mitch Wheat

몇 년 전 SQL S.가 상관 쿼리 처리에 최적화되어 있다는 사실에 놀랐습니다. 간단한 쿼리의 경우 JOIN을 사용하여 논리적으로 동등한 쿼리와 동일한 실행 계획을 얻습니다. 또한 Oracle을 무릎에 닿게하는 상관 된 쿼리는 SQL S에서 느리게 실행됩니다.!
Joe Pineda

그래서 나는 항상 두 가지 방법으로 테스트합니다. 그리고 나는 보통 두 가지 방법으로 시도합니다. 실제로 SQL Server의 경우 일반적으로 상관 된 sq가 느리지 않음을 알았습니다.
dkretz

3
상관 된 하위 쿼리와 조인은 IDENTICAL (대부분의 경우)임을 이해하십시오. 그것들은 서로 최적화 된 것이 아니라 동일한 작업에 대한 다른 텍스트 표현입니다.
erikkallen 2009

5

임시 테이블, 특히 SQL Server에서 Oracle로 전환하는 사람들은 임시 테이블을 과도하게 사용하는 습관이 있습니다. 중첩 된 select 문만 사용하십시오.


5

SQL 응용 프로그램 (개별 쿼리 및 다중 사용자 시스템 모두)이 빠르거나 느리게 만드는 이유에 대한 좋은 아이디어없이 쿼리를 작성하는 개발자. 여기에는 다음에 대한 무지가 포함됩니다.

  • 대부분의 쿼리 병목 현상이 CPU가 아닌 I / O 인 경우의 물리적 I / O 최소화 전략
  • 여러 종류의 물리적 스토리지 액세스에 대한 성능 영향 (예 : 물리적 스토리지가 SSD 인 경우 적은 수의 순차적 인 I / O가 많은 소규모 임의 I / O보다 빠를 것입니다!)
  • DBMS가 잘못된 쿼리 계획을 생성하는 경우 쿼리를 수동으로 조정하는 방법
  • 데이터베이스 성능 저하 진단, 느린 쿼리 "디버그"방법 및 쿼리 계획을 읽는 방법 (선택한 DBMS에 따라 EXPLAIN)
  • 다중 사용자 애플리케이션에서 처리량을 최적화하고 교착 상태를 피하기위한 잠금 전략
  • 데이터 세트 처리를 처리하기위한 배치 및 기타 트릭의 중요성
  • 공간과 성능의 균형을 최상으로 유지하기위한 테이블 및 인덱스 디자인 (예 : 인덱스 커버링, 가능한 경우 인덱스를 작게 유지, 필요한 최소 크기로 데이터 유형 축소 등)

3

영광스러운 ISAM (Indexed Sequential Access Method) 패키지로 SQL 사용. 특히, SQL 문을 하나의 큰 명령문으로 결합하는 대신 커서를 중첩합니다. 실제로 옵티마이 저가 할 수있는 것이 많지 않기 때문에 이것은 옵티마이 저의 남용으로 간주됩니다. 이것은 비 효율성을 극대화하기 위해 준비되지 않은 진술과 결합 될 수 있습니다.

DECLARE c1 CURSOR FOR SELECT Col1, Col2, Col3 FROM Table1

FOREACH c1 INTO a.col1, a.col2, a.col3
    DECLARE c2 CURSOR FOR
        SELECT Item1, Item2, Item3
            FROM Table2
            WHERE Table2.Item1 = a.col2
    FOREACH c2 INTO b.item1, b.item2, b.item3
        ...process data from records a and b...
    END FOREACH
END FOREACH

올바른 해결책은 (거의 항상) 두 개의 SELECT 문을 하나로 결합하는 것입니다.

DECLARE c1 CURSOR FOR
    SELECT Col1, Col2, Col3, Item1, Item2, Item3
        FROM Table1, Table2
        WHERE Table2.Item1 = Table1.Col2
        -- ORDER BY Table1.Col1, Table2.Item1

FOREACH c1 INTO a.col1, a.col2, a.col3, b.item1, b.item2, b.item3
    ...process data from records a and b...
END FOREACH

이중 루프 버전의 유일한 장점은 내부 루프가 끝나기 때문에 Table1의 값 사이를 쉽게 구분할 수 있다는 것입니다. 이는 제어 중단 보고서에 영향을 줄 수 있습니다.

또한 응용 프로그램에서의 정렬은 일반적으로 아니오입니다.


이 구문은 아니지만 스타일은 특히 PHP 환경에서 두드러집니다.
dkretz

구문은 실제로 IBM Informix-4GL이지만 설명 방법이 많이 필요하지 않다는 것은 분명합니다 (제 생각에). 그리고 스타일은 프로그래밍 언어에 관계없이 많은 SQL 프로그램에서 만연합니다.
Jonathan Leffler

반 패턴을 설명하기 위해 잘 알려진 반 패턴 (암시 적 조인)을 사용한다는 사실을 제외하고는 요점을 무너 뜨립니다.
요한

물론 커서 사용은 SQ1 반 패턴입니다. 사실상 모든 커서를 세트 기반 작업으로 다시 작성할 수 있습니다. 수년 간의 경험이 있고 datbase 작업의 내부가 어떻게 작성되어야 하는지를 이해하는 DBA만이 할 수있는 것은 소수입니다. 응용 프로그램 개발자는 SQL 커서를 작성할 필요가 없습니다.
HLGEM

3

기본 키를 레코드 주소의 대용으로 사용하고 외래 키를 레코드에 포함 된 포인터의 대용으로 사용

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.