가장 일반적인 SQL 안티 패턴은 무엇입니까?
관계형 데이터베이스를 사용하는 우리 모두는 SQL이 다르다는 것을 알고 있습니다(또는 배우고 있습니다).원하는 결과를 도출하고 효율적으로 수행하는 것은 부분적으로 익숙하지 않은 패러다임을 학습하고 가장 익숙한 프로그래밍 패턴 중 일부가 여기서 작동하지 않는다는 것을 알아내는 지루한 과정을 수반합니다.당신이 본 (혹은 당신이 저지른) 공통적인 반감은 무엇입니까?
대부분의 프로그래머가 데이터 액세스 레이어에 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 계층에 밀접하게 결합하기 때문에 매우 취약합니다.또한 이러한 유형의 프로그래밍은 저장 프로시저를 재사용할 수 없도록 철저히 방지합니다.
제 3위입니다.
1번.필드 목록을 지정하지 못했습니다. (편집: 혼란을 방지하기 위해: 프로덕션 코드 규칙입니다.내가 작성자가 아닌 한 일회성 분석 스크립트에는 적용되지 않습니다.)
SELECT *
Insert Into blah SELECT *
그래야 한다
SELECT fieldlist
Insert Into blah (fieldlist) SELECT fieldlist
2번.커서 및 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
3번.Date Logic ~ 문자열 유형
--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 텍스트에 대해 하나의 실행 계획만 생성되어 캐시에 고정됩니다.그 플랜은 파라미터의 값에 관계없이 사용됩니다.이로 인해 퍼포먼스가 간헐적으로 저하됩니다.2개의 쿼리(원하는 실행 계획당 1개의 쿼리)를 작성하는 것이 훨씬 좋습니다.
사람이 읽을 수 있는 패스워드 필드(예:ad).자기 설명.
색인화된 컬럼에 LIKE를 사용하면서, 저는 그냥 LIKE라고 말하고 싶을 정도입니다.
SQL에서 생성된 PK 값을 재활용하는 중입니다.
놀랍게도 아직 아무도 신의 식탁에 대해 언급하지 않았다.100개의 비트 플래그, 큰 문자열 및 정수 열만큼 "유기적"을 나타내는 것은 없습니다.
다음으로 CSV, 파이프 구분 문자열 또는 기타 필요한 데이터를 큰 텍스트 필드에 저장하는 "I miss .ini files" 패턴이 있습니다.
MS SQL 서버의 경우 커서를 사용합니다.주어진 커서 작업을 수행하는 더 나은 방법이 있습니다.
너무 많아서 편집!
깊이 파고들 필요가 없다: 준비된 문장을 사용하지 않는다.
의미 없는 테이블 에일리어스 사용:
from employee t1,
department t2,
job t3,
...
큰 SQL 문을 읽는 것이 필요 이상으로 어려워진다.
var query = "select COUNT(*) from Users where UserName = '"
+ tbUser.Text
+ "' and Password = '"
+ tbPassword.Text +"'";
- 사용자 입력을 맹목적으로 신뢰하다
- 매개 변수화된 쿼리 사용 안 함
- 클리어텍스트 패스워드
내 관심사는 상무이사의 절친한 친구 개 미용사의 8살 아들이 만든 450개 컬럼의 액세스 테이블과 데이터 구조를 제대로 정규화하는 방법을 모르기 때문에 존재하는 의심스러운 룩업 테이블입니다.
일반적으로 이 룩업테이블은 다음과 같습니다.
ID INT,이름: NVARCHAR(132),IntValue1 INT,IntValue2 INT,CharValue 1 NVARCHAR(255),CharValue2 NVARCHAR(255),Date1 DATETIME,날짜 2 DATETIME
이런 혐오스러운 것에 의존하는 시스템을 가진 고객들의 수는 셀 수 없을 정도입니다.
제가 제일 싫어하는 건
테이블, sproc 등을 작성할 때 공백 사용Camel Case나 under_scores, 단수 또는 복수형, 대문자 또는 소문자도 상관없습니다만, 특히 [스페이스가 있는] 테이블이나 컬럼을 참조해야 합니다(예, 이것과 마주친 적이 있습니다.
정규화 해제된 데이터테이블이 완전히 정규화될 필요는 없지만, 현재 평가 점수나 주요 항목에 대한 정보가 있는 테이블과 마주쳤을 때 어느 시점에서 테이블을 따로 만들어 동기화해야 할 것 같습니다.우선 데이터를 정상화하고, 그 후에 정규화를 해제하는 것이 도움이 되는 장소를 발견하면 검토하겠습니다.
보기 또는 커서 중 하나를 과도하게 사용합니다.뷰에는 목적이 있지만 각 테이블을 뷰로 감싸면 너무 과합니다.커서를 여러 번 사용해야 했지만 일반적으로 다른 메커니즘을 사용할 수 있습니다.
접근. 프로그램이 안티 패턴일 수 있나요?저희 회사에는 SQL Server가 있지만, 많은 사람들이 SQL Server의 가용성, 사용 편의성 및 비기술 사용자와의 친화성 때문에 액세스를 사용하고 있습니다.여기엔 너무 많은 것들이 있지만, 만약 당신이 비슷한 환경을 겪어봤다면, 당신은 알 것이다.
시간 값을 저장하려면 UTC 시간대만 사용해야 합니다.현지 시간을 사용하면 안 됩니다.
SP는 커스텀 프로시저가 아닌 시스템 프로시저 위치에서 먼저 검색되기 때문에 스토어 프로시저 이름의 접두사로 사용합니다.
임시 테이블 및 커서 과다 사용.
SCOPE_IDENTY() 대신 @@IDENTY를 사용합니다.
- @@IDENTY는 현재 세션 내의 모든 테이블에 대해 생성된 마지막 ID 값을 모든 범위에서 반환합니다.여기는 여러 범위에 걸쳐있기 때문에 조심해야 합니다.현재 스테이트먼트 대신 트리거에서 값을 얻을 수 있습니다.
- SCOPE_IDENTY는 현재 세션과 현재 스코프의 모든 테이블에 대해 생성된 마지막 ID 값을 반환합니다.일반적으로 사용하고 싶은 것.
- IDENT_CURRENT는 세션 및 스코프의 특정 테이블에 대해 마지막으로 생성된 ID 값을 반환합니다.이렇게 하면 위의 두 개의 값이 필요한 수준(매우 드문 경우)이 아닌 경우 값을 원하는 테이블을 지정할 수 있습니다.레코드를 삽입하지 않은 테이블의 현재 ID 값을 가져오려면 이 옵션을 사용할 수 있습니다.
사용자 데이터를 Fax 필드에 저장하는 등 의도하지 않은 용도로 '데드' 필드를 재사용하는 것은 매우 매력적입니다. 단, 빠른 수정으로 매우 매력적입니다.
select some_column, ...
from some_table
group by some_column
결과가 some_column별로 정렬된다고 가정합니다.(현재로서는) 이 가정이 성립하는 Sybase에서 조금 본 적이 있습니다.
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
아니면 한 줄에 모든 것을 쑤셔넣는 것.
FROM TableA, TableB WHERE
FROM TableA INNER JOIN TableB ON
쿼리가 특정 방식으로 반환된다고 가정하는 경우, ORDER BY 절을 삽입하지 않고 특정 방식으로 정렬됩니다. 쿼리 툴에 테스트 중에 쿼리가 표시되었기 때문입니다.
경력 첫 6개월 동안 SQL을 배우고 이후 10년 동안 다른 것을 배우지 못했습니다.특히 윈도우 설정/분석 SQL 기능을 학습하지 않거나 효과적으로 사용하지 않습니다.특히 over()와 partition by를 사용합니다.
창 함수는 집계 함수와 마찬가지로 정의된 행 집합(그룹)에 대해 집계를 수행하지만 창 함수는 그룹당 하나의 값을 반환하지 않고 각 그룹에 대해 여러 값을 반환할 수 있습니다.
윈도우 기능에 대한 자세한 내용은 O'Reilly SQL Cookbook 부록 A를 참조하십시오.
목록을 완성하기 위해서 내가 좋아하는 걸 여기에 넣어야 해내가 가장 좋아하는 반격은 당신의 질문을 테스트하지 않는 것입니다.
이는 다음 경우에 적용됩니다.
- 쿼리에 여러 테이블이 포함되어 있습니다.
- 질의를 위한 최적의 설계가 있다고 생각되지만, 굳이 가정을 테스트하지 않아도 됩니다.
- 첫 번째 쿼리는 최적화에 가까운지 여부에 대한 단서가 없이 받아들여집니다.
또한 비정형 데이터나 불충분한 데이터에 대한 테스트는 모두 반영되지 않습니다.저장 프로시저인 경우 테스트 스테이트먼트를 코멘트에 넣고 결과와 함께 저장합니다.그 이외의 경우는, 코드의 코멘트에 결과와 함께 입력합니다.
일시적인 테이블 남용
구체적으로는 다음과 같습니다.
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에서 이 형식의 코드 페이지를 본 적이 있습니다.
여기 SO에 대한 SQL 응답 중 일부를 바탕으로 이 데이터를 정리했습니다.
트리거가 OOP에 대한 이벤트핸들러와 마찬가지로 데이터베이스에 대한 것이라고 생각하는 것은 심각한 반대입니다.테이블에서 트랜잭션(이벤트)이 발생했을 때 트리거가 되는 오래된 논리가 있을 수 있다는 인식이 있습니다.
그렇지 않아요.큰 차이점 중 하나는 트리거가 복수 동작과 동기화된다는 것입니다. 왜냐하면 트리거는 행 동작이 아닌 설정된 동작에서 동기화되기 때문입니다.OOP 측에서는 정반대의 이벤트가 비동기 트랜잭션을 구현하는 효율적인 방법입니다.
반대되는 견해: 정상화에 대한 과도한 집착.
대부분의 SQL/RBDB 시스템은 정규화되지 않은 데이터에서도 매우 유용한 기능(트랜잭션, 복제)을 1개 제공합니다.디스크 공간은 저렴하고, 1NF 스키마를 써넣는 것보다, 가져온 데이터를 조작/필터링/검색하는 것이, 모든 귀찮은 일(복잡한 조인, 귀찮은 서브 셀렉트 등)에 간단하게 대처할 수 있는 경우가 있습니다.
과잉 정규화된 시스템은 특히 초기 개발 단계에서 시기상조인 경우가 많다는 것을 알게 되었습니다.
(더 많은 생각...)http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/)
설명 없이 저장 프로시저 또는 함수...
1) 공식 안티 패턴인지는 모르지만, 데이터베이스 컬럼의 매직 값으로서의 스트링 리터럴은 싫어하고 피하려고 합니다.
미디어의 예Wiki의 표 '이미지':
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 테이블을 조회하는 등의 케이스를 설계하고 있습니다.
2) 특정 NLS 설정에 의존하는 날짜/문자열 변환
CONVERT(NVARCHAR, GETDATE())
형식 식별자 없음
쿼리에서 동일한 하위 쿼리입니다.
변경된 보기 - 너무 자주 변경되고 예고나 이유 없이 변경된 보기입니다.변경은 가장 부적절한 시기에 발견되거나 잘못되어 전혀 눈치채지 못할 것입니다.누군가가 그 칼럼에 더 좋은 이름을 생각해냈기 때문에 당신의 어플리케이션이 망가질지도 모릅니다.규칙 뷰는 소비자와의 계약을 유지하면서 기본 테이블의 유용성을 확장해야 합니다.문제를 수정하되 기능을 추가하거나 더 나쁜 변경 동작을 하지 마십시오. 그러면 새 보기가 생성됩니다.경감하려면 , 다른 프로젝트와 뷰를 공유하지 말아 주세요.또, 플랫폼이 허가하는 경우는, CTE 를 사용해 주세요.점포에 DBA가 있는 경우 뷰를 변경할 수 없지만 이 경우 모든 뷰가 구식이거나 무용지물이 됩니다.
!Paramed - 쿼리는 여러 목적을 가질 수 있습니까?아마 다음번 책을 읽는 사람은 깊은 명상을 해 봐야 알 수 있을 것이다.지금 당장 필요하지 않더라도 디버깅하는 것이 "정당한" 경우에도 그럴 가능성이 높습니다.파라미터를 추가하면 유지보수 시간이 단축되고 건조 상태가 유지됩니다.where 절이 있는 경우 파라미터를 지정해야 합니다.
케이스 없음 -
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
퍼포먼스 면에서 비용이 많이 들 수 있는 것은 다음 2가지입니다.
설정 기반 식 대신 커서 사용.프로그래머가 절차적으로 생각할 때 이런 일이 자주 일어나는 것 같아요.
연관된 하위 쿼리를 사용하여 파생된 테이블에 조인하여 작업을 수행할 수 있는 경우.
SQL 애플리케이션(개별 쿼리 및 다중 사용자 시스템 모두)의 속도를 높이거나 느리게 만드는 이유에 대해 제대로 알지 못한 채 쿼리를 작성하는 개발자.여기에는 다음 사항에 대한 무지가 포함됩니다.
- 대부분의 쿼리의 병목현상이 CPU가 아닌 I/O이기 때문에 물리 I/O 최소화 전략
- 다양한 종류의 물리적 스토리지 액세스가 성능에 미치는 영향(예: 다수의 순차 I/O가 많은 소규모 랜덤 I/O보다 빠릅니다만, 물리적 스토리지가 SSD인 경우에는 더 빠릅니다!)
- DBMS에서 잘못된 쿼리 계획이 생성된 경우 쿼리를 수동으로 조정하는 방법
- 데이터베이스 성능 저하 진단 방법, 느린 쿼리 "디버깅" 방법 및 쿼리 계획 읽기(또는 선택한 DBMS에 따라 설명)
- 잠금 전략으로 스루풋을 최적화하고 다중 사용자 애플리케이션의 교착 상태를 방지합니다.
- 데이터 세트의 처리를 처리하기 위한 배치 처리 및 기타 요령의 중요성
- 공간과 성능의 균형을 가장 잘 맞추기 위한 테이블 및 인덱스 설계(예: 인덱스 커버, 가능한 한 인덱스 작게 유지, 데이터 유형을 필요한 최소 크기로 줄이는 등)
특히 SQL Server에서 Oracle로 전환하는 사람들은 임시 테이블을 과도하게 사용하는 경향이 있습니다.중첩된 select 문을 사용합니다.
레코드 주소의 대용으로서 프라이머리 키를 사용하고, 레코드에 내장된 포인터의 대용으로서 외부 키를 사용합니다.
응용 프로그램 참여 SQL 문제뿐만 아니라 문제에 대한 설명을 찾고 이 질문을 찾았을 때 목록에 없는 것에 놀랐습니다.
어플리케이션 조인은 사용하는 문구를 들었습니다만, 2개 이상의 테이블에서 행 세트를 꺼내 루프용으로 네스트된 쌍과 함께 (Java) 코드로 결합하는 것입니다.따라서 시스템(앱 및 데이터베이스)은 전체 교차 제품을 식별하고 이를 검색하여 애플리케이션에 전송해야 합니다.앱이 크로스 제품을 데이터베이스만큼 빠르게 필터링할 수 있다고 가정할 때, 결과 세트를 빨리 잘라내는 것만으로 데이터 전송이 줄어듭니다.
언급URL : https://stackoverflow.com/questions/346659/what-are-the-most-common-sql-anti-patterns
'programing' 카테고리의 다른 글
iOS에서 이메일 주소가 유효한지 확인합니다. (0) | 2023.04.23 |
---|---|
Swift에서 UITextView에 자리 표시자 텍스트를 추가하시겠습니까? (0) | 2023.04.23 |
"이 디렉토리 또는 페이지를 볼 수 있는 권한이 없습니다"를 디버깅하는 방법 (0) | 2023.04.23 |
산점도 점의 레이블을 이름으로 지정하는 방법은 무엇입니까? (0) | 2023.04.23 |
지정된 서수(Excel에서)를 날짜로 변환하는 방법 (0) | 2023.04.23 |