programing

응용 프로그램 개발자가 저지른 데이터베이스 개발 실수

cafebook 2023. 10. 30. 21:16
반응형

응용 프로그램 개발자가 저지른 데이터베이스 개발 실수

애플리케이션 개발자들이 흔히 저지르는 데이터베이스 개발 실수는 무엇입니까?

1. 적절한 지수를 사용하지 않음

이것은 비교적 쉬운 일이지만 여전히 항상 일어납니다.외국 키에는 인덱스가 있어야 합니다.필드를 사용하는 경우WHERE당신은 probably에 색인을 달아야 합니다.이러한 인덱스는 실행해야 하는 쿼리를 기준으로 여러 열을 포함하는 경우가 많습니다.

2. 참조 무결성을 적용하지 않음

데이터베이스는 여기서 다를 수 있지만 데이터베이스가 참조 무결성(모든 외부 키가 존재하는 엔티티를 가리킬 수 있음)을 지원하는 경우에는 이를 사용해야 합니다.

MySQL 데이터베이스에서 이러한 장애가 발생하는 것은 매우 일반적인 일입니다.저는 제 ISAM이 그걸 지지한다고 생각하지 않습니다.InnoDB는 합니다.MyISAM을 사용하는 사람이나 InnoDB를 사용하지만 사용하지 않는 사람을 찾을 수 있습니다.

자세한 내용:

3. 대리(기술) 기본 키가 아닌 자연스러운 키 사용

자연 키는 (외관적으로) 독특한 외부적으로 의미 있는 데이터에 기반을 둔 키입니다.일반적인 예로는 제품 코드, 두 글자로 된 주 코드(미국), 주민등록번호 등이 있습니다.대리 키 또는 기술적 기본 키는 시스템 외부에서 전혀 의미가 없는 키입니다.이는 순수하게 엔티티를 식별하기 위해 개발되었으며 일반적으로 자동 증가 필드(SQL Server, MySQL 등) 또는 시퀀스(특히 Oracle)입니다.

제 생각에 당신은 항상 대리 키를 사용해야 합니다.이 문제는 다음과 같은 질문에 제기됩니다.

이것은 당신이 보편적인 동의를 얻지 못할 다소 논란이 많은 주제입니다.어떤 상황에서는 자연 키가 괜찮다고 생각하는 사람들을 발견할 수도 있지만, 대리 키가 거의 불필요하다는 것 외에는 다른 어떤 비판도 발견할 수 없을 것입니다.그것은 저에게 물어보시면 아주 작은 단점입니다.

심지어 국가들도 존재하지 않을 수 있다는 것을 기억하세요 (예: 유고슬라비아).

4개가 . 다음이 필요한 쿼리 작성DISTINCT일하기 위해

ORM 생성 쿼리에서 종종 볼 수 있습니다.Hibernate에서 로그 출력을 보면 다음으로 시작하는 모든 쿼리가 표시됩니다.

SELECT DISTINCT ...

이것은 중복된 행을 반환하지 않고 중복된 개체를 얻을 수 있도록 보장하는 약간의 지름길입니다.가끔 이런 사람들도 볼 수 있을 겁니다.너무 많이 보면 진짜 빨간 깃발입니다.그거 말고요DISTINCT나쁘거나 유효한 응용 프로그램이 없습니다.이것은 (두 가지 카운트 모두에서) 가능하지만, 올바른 쿼리를 작성하기 위한 대리인이나 임시방편은 아닙니다.

내가 DISTINCT를 싫어하는 이유:

제 생각에 일이 잘못되기 시작한 것은 개발자가 상당한 쿼리를 만들고 테이블을 결합하고 있는데 갑자기 자신이 중복(또는 더 많은) 행을 얻고 있는 것처럼 보인다는 것을 깨닫고 즉각적인 응답을 할 때입니다.이 "문제"에 대한 그의 "해결책"은 DISTINCT 키워드를 사용하여 모든 문제를 해결하는 것입니다.

5. 조인보다 집계 선호

데이터베이스 애플리케이션 개발자들이 흔히 저지르는 또 다른 실수는 얼마나 많은 비용이 드는 집계(즉,GROUP BY절)을 조인에 비유할 수 있습니다.

이것이 얼마나 널리 퍼져 있는지에 대해 알기 위해, 저는 여기서 이 주제에 대해 여러 차례 글을 썼지만, 그것에 대해 많은 반대를 받았습니다.예를 들어,

SQL 문에서 - "참여" vs "그룹별 및 보유":

첫번째 쿼리:

SELECT userid
FROM userrole
WHERE roleid IN (1, 2, 3)
GROUP by userid
HAVING COUNT(1) = 3

쿼리 시간: 0.312초

두번째 쿼리:

SELECT t1.userid
FROM userrole t1
JOIN userrole t2 ON t1.userid = t2.userid AND t2.roleid = 2
JOIN userrole t3 ON t2.userid = t3.userid AND t3.roleid = 3
AND t1.roleid = 1

쿼리 시간: 0.016초

맞아요.제가 제안한 join 버전은 aggregate 버전보다 20배 빠릅니다.

6. 보기를 통해 복잡한 쿼리를 단순화하지 않음

모든 데이터베이스 공급업체가 보기를 지원하는 것은 아니지만, 보기를 지원하는 공급업체의 경우 신중하게 사용할 경우 쿼리를 크게 단순화할 수 있습니다.예를 들어, 한 프로젝트에서 일반적인 파티 모델을 CRM에 사용했습니다.이는 매우 강력하고 유연한 모델링 기법이지만 많은 결합을 유도할 수 있습니다.이 모델에는 다음이 있습니다.

  • 파티: 사람들과 조직;
  • 당사자 역할: 당사자가 수행한 작업(예: 종업원 및 고용주)
  • 당사자 역할 관계: 해당 역할들이 서로 어떻게 연관되어 있는지.

예:

  • 테드는 당의 하위 유형인 사람입니다.
  • 테드는 많은 역할을 맡았고, 그 중 하나가 직원입니다.
  • 인텔은 당사자의 하위 유형인 조직입니다.
  • Intel에는 여러 역할이 있으며 그 중 하나가 고용주입니다.
  • 인텔은 테드를 고용하고 있는데, 이는 각자의 역할 사이에 관계가 있다는 것을 의미합니다.

그래서 테드를 고용주와 연결하기 위해 5개의 테이블이 결합되어 있습니다.모든 직원을 조직이 아닌 개인으로 가정하고 다음과 같은 도우미 보기를 제공합니다.

CREATE VIEW vw_employee AS
SELECT p.title, p.given_names, p.surname, p.date_of_birth, p2.party_name employer_name
FROM person p
JOIN party py ON py.id = p.id
JOIN party_role child ON p.id = child.party_id
JOIN party_role_relationship prr ON child.id = prr.child_id AND prr.type = 'EMPLOYMENT'
JOIN party_role parent ON parent.id = prr.parent_id = parent.id
JOIN party p2 ON parent.party_id = p2.id

그리고 갑자기 원하는 데이터를 매우 간단하게 볼 수 있지만 매우 유연한 데이터 모델을 사용할 수 있게 됩니다.

7. 입력을 검사하지 않음

이거 엄청 크네요.지금은 PHP를 좋아하지만 무엇을 하고 있는지 모르면 공격에 취약한 사이트를 만드는 것은 정말 쉽습니다.작은 바비 테이블스의 이야기만큼 요약되는 것은 없습니다.

URL, 양식 데이터 및 쿠키를 통해 사용자가 제공하는 데이터는 항상 적대적인 것으로 취급되고 소독되어야 합니다.당신이 기대하는 것을 얻고 있는지 확인하세요.

8. 준비된 명세서 미사용

준비된 문은 쿼리를 컴파일할 때 삽입, 업데이트 및WHERE절을 작성한 다음 나중에 제공합니다.예를 들어,

SELECT * FROM users WHERE username = 'bob'

SELECT * FROM users WHERE username = ?

아니면

SELECT * FROM users WHERE username = :username

당신의 플랫폼에 따라.

데이터베이스가 이렇게 함으로써 그들의 무릎을 꿇는 것을 보았습니다.기본적으로 현대 데이터베이스는 새로운 쿼리를 접할 때마다 컴파일해야 합니다.이전에 조회된 쿼리가 발생하면 데이터베이스에 컴파일된 쿼리와 실행 계획을 캐시할 수 있는 기회를 제공하는 것입니다.쿼리를 많이 수행하면 데이터베이스가 이를 파악하고 그에 따라 최적화할 수 있는 기회를 얻을 수 있습니다(예: 컴파일된 쿼리를 메모리에 고정함).

준비된 문을 사용하면 특정 쿼리가 얼마나 자주 사용되는지에 대한 의미 있는 통계도 얻을 수 있습니다.

또한 준비된 문은 SQL 주입 공격으로부터 보다 효과적으로 보호할 수 있습니다.

9. 정규화가 충분하지 않음

데이터베이스 정규화는 기본적으로 데이터베이스 설계를 최적화하거나 데이터를 테이블로 구성하는 과정입니다.

바로 이번 주에 저는 누군가가 배열을 삽입하여 데이터베이스의 단일 필드에 삽입한 어떤 코드를 우연히 발견했습니다.정규화는 해당 배열의 요소를 하위 테이블의 별도 행(즉, 일대일 관계)으로 처리하는 것입니다.

이는 사용자 ID 목록을 저장하는 최상의 방법으로도 나타납니다.

다른 시스템에서는 리스트가 직렬 PHP 배열로 저장되어 있는 것을 보았습니다.

하지만 정상화의 부족은 여러 형태로 나타납니다.

추가:

10. 정규화가 너무 심합니다.

이것은 이전의 점과 모순되는 것처럼 보일 수 있지만, 정상화는 많은 것들과 마찬가지로 도구입니다.그것은 목적을 위한 수단이지 그 자체가 목적이 아닙니다.많은 개발자들이 이것을 잊고 "수단"을 "목적"으로 취급하기 시작했다고 생각합니다.유닛 테스트가 그 대표적인 예입니다.

저는 한때 다음과 같은 작업을 수행한 고객을 위해 거대한 계층 구조를 가진 시스템에 대해 작업한 적이 있습니다.

Licensee ->  Dealer Group -> Company -> Practice -> ...

의미 있는 데이터를 얻기 전에 약 11개의 테이블을 함께 결합해야 합니다.그것은 정상화가 지나치게 진행된 좋은 예였습니다.

더 중요한 것은 신중하고 고려된 비규격화는 엄청난 성능상의 이점을 가져올 수 있지만 이를 수행할 때는 정말 조심해야 합니다.

추가:

11. 배타적 호 사용

배타적 호(exclusive arc)는 두 개 이상의 외래 키를 사용하여 테이블을 만드는 일반적인 실수이며, 하나만 null이 아닐 수 있습니다.큰 실수.우선 데이터 무결성을 유지하는 것이 훨씬 더 어려워집니다.결국 참조 무결성이 있더라도 이들 외부 키 중 2개 이상을 설정하는 것을 방해하는 것은 없습니다(복잡한 점검 제약에도 불구하고).

관계형 데이터베이스 설계에 대한 실용적 가이드:

코드 작성이 어색하고 유지보수에 어려움이 있을 수 있으므로 가능한 한 단독 아크 시공을 하지 말 것을 강력히 권고했습니다.

12. 쿼리에 대한 성능 분석을 전혀 수행하지 않음

특히 데이터베이스 세계에서는 실용주의가 압도적입니다.원칙이 독단적인 것이 될 정도로 원칙을 고수하고 있다면 아마도 실수를 했을 것입니다.위에서 집계 쿼리의 예를 들어 보겠습니다.애그리게이트 버전은 "멋져 보일 수 있지만 성능은 형편없습니다.성과를 비교하는 것은 논쟁을 끝냈어야 했지만(그렇지는 않았습니다), 요점을 더 강조합니다. 애당초 그러한 잘못된 정보에 입각한 견해를 말하는 것은 무지하고, 심지어 위험하기까지 합니다.

13. UNION ALL, 특히 UNION 건설에 대한 과도한 의존

SQL 용어의 UNION은 일치하는 데이터 집합을 연결할 뿐이며, 이는 데이터 집합의 유형과 열의 개수가 동일하다는 것을 의미합니다.그들 사이의 차이점은 UNION ALL은 단순한 연결이고 가능한 한 선호되어야 하는 반면 UNION은 암묵적으로 중복 튜플을 제거하기 위해 DISTINCT를 할 것이라는 것입니다.

UNION은 DISTINCT와 마찬가지로 각자의 자리를 가지고 있습니다.유효한 응용프로그램이 있습니다.하지만 만약 여러분이 그것들을 많이 하고 있다는 것을 발견한다면, 특히 서브쿼리에서, 여러분은 아마도 뭔가 잘못하고 있는 것입니다.쿼리 구성이 부실하거나 데이터 모델이 제대로 설계되지 않아 이러한 작업을 수행해야 하는 경우일 수 있습니다.

UNION은 특히 조인 또는 종속 하위 쿼리에 사용될 경우 데이터베이스를 손상시킬 수 있습니다.가능할 때마다 피하도록 하세요.

14. 쿼리에서 OR 조건 사용

무해한 것 같습니다.결국 AND는 괜찮습니다.아니면 괜찮으실까요?틀렸어.기본적으로 AND 조건은 데이터 세트를 제한하는 반면 OR 조건은 데이터 세트를 성장시키지만 최적화에 도움이 되는 방식은 아닙니다.특히 다른 OR 조건이 교차할 수 있는 경우, 최적화기가 결과에 대해 효과적으로 DISTINCT 연산을 수행하도록 강요합니다.

나쁨:

... WHERE a = 2 OR a = 5 OR a = 11

더 나은 정보:

... WHERE a IN (2, 5, 11)

이제 SQL Optimizer는 첫 번째 쿼리를 두 번째 쿼리로 효과적으로 변환할 수 있습니다.하지만 아닐 수도 있습니다.그냥 하지 마.

15. 고성능 솔루션을 제공하도록 데이터 모델을 설계하지 않음

이것은 정량화하기 어려운 점입니다.일반적으로 효과에 따라 관찰됩니다.비교적 간단한 작업에 대해 쿼리를 거의 작성하지 않거나 비교적 간단한 정보를 찾기 위한 쿼리가 효율적이지 않다는 것을 알게 되면 데이터 모델이 좋지 않을 수 있습니다.

어떤 면에서는 이 점이 이전의 모든 것을 요약하지만 쿼리 최적화와 같은 작업을 수행하는 것은 종종 두 번째 작업을 수행해야 할 때 먼저 수행된다는 점에서 주의해야 할 사항에 가깝습니다.무엇보다도 성능을 최적화하기 전에 좋은 데이터 모델을 확보해야 합니다.크누스의 말대로라면

섣부른 최적화는 모든 악의 근원입니다.

16. 데이터베이스 트랜잭션의 잘못된 사용

특정 공정에 대한 모든 데이터 변경은 원자 단위여야 합니다.즉, 작업이 성공하면 완전히 성공합니다.실패할 경우 데이터는 변경되지 않습니다. - '반쪽' 변경 가능성이 없어야 합니다.

이상적으로, 이를 달성하기 위한 가장 간단한 방법은 전체 시스템 설계가 단일 INSERT/UPDATE/DEELETE 문을 통해 모든 데이터 변경을 지원하기 위해 노력해야 하는 것입니다.이 경우 데이터베이스 엔진이 자동으로 처리해야 하므로 특별한 트랜잭션 처리가 필요하지 않습니다.

그러나 데이터를 일관된 상태로 유지하기 위해 하나의 단위로 여러 개의 문을 수행해야 하는 프로세스가 있다면 적절한 트랜잭션 제어가 필요합니다.

  • 첫 번째 문장 전에 트랜잭션을 시작합니다.
  • 마지막 문장 뒤에 트랜잭션을 커밋합니다.
  • 오류가 발생하면 트랜잭션을 롤백합니다.그리고 아주 NB!오류 후에 이어지는 모든 문장을 생략/중단하는 것을 잊지 마십시오.

이와 관련하여 데이터베이스 연결 계층과 데이터베이스 엔진이 상호 작용하는 방식의 세부 특성에도 주의를 기울이는 것이 좋습니다.

17. '집합 기반' 패러다임을 이해하지 못함

SQL 언어는 특정 유형의 문제에 적합한 특정 패러다임을 따릅니다.다양한 벤더별 확장에도 불구하고, 이 언어는 자바, C#, 델파이 등과 같은 언어에서 사소한 문제들을 다루기가 어렵습니다.

이러한 이해의 부족은 몇 가지 방식으로 드러납니다.

  • 데이터베이스에 너무 많은 절차적 또는 명령적 논리를 부과하는 것은 부적절합니다.
  • 커서의 부적절하거나 과도한 사용.특히 질문 하나면 충분할 때.
  • 다중 행 업데이트에서 영향을 받는 행당 한 번씩 트리거가 발생한다고 잘못 가정합니다.

명확한 책임 구분을 결정하고, 각 문제를 해결하기 위해 적절한 도구를 사용하도록 노력합니다.

개발자의 주요 데이터베이스 설계 및 프로그래밍 오류

  • 이기적인 데이터베이스 설계 및 사용.개발자들은 종종 데이터의 다른 이해관계자들의 요구를 고려하지 않고 데이터베이스를 개인 영구 객체 저장소로 취급합니다.이는 애플리케이션 설계자에게도 적용됩니다.데이터베이스 설계와 데이터 무결성이 열악하기 때문에 제3자가 데이터를 처리하는 것이 어려워지고 시스템의 수명 주기 비용이 크게 증가할 수 있습니다.보고 및 MIS는 애플리케이션 설계에 있어서 서투른 사촌으로 간주되는 경향이 있으며, 사후적으로 수행될 뿐입니다.

  • 정규화되지 않은 데이터를 남용합니다.정규화되지 않은 데이터를 과도하게 사용하여 애플리케이션 내에서 유지 관리하는 것이 데이터 무결성 문제의 해결책입니다.비정규화를 거의 사용하지 않습니다.쿼리에 조인을 추가하고 싶지 않다고 해서 정규화를 취소할 수는 없습니다.

  • SQL 작성이 두렵습니다.SQL은 로켓 과학이 아니며 실제로 업무를 잘 수행합니다.O/R 매핑 계층은 단순하고 해당 모델에 잘 맞는 쿼리의 95%를 매우 잘 수행합니다.때로는 SQL이 작업을 수행하는 가장 좋은 방법이기도 합니다.

  • 독단적 '저장 프로시저 없음' 정책.저장 프로시저가 사악하다고 믿든 상관없이, 이런 종류의 독단적인 태도는 소프트웨어 프로젝트에서 설 자리가 없습니다.

  • 데이터베이스 설계를 이해할 수 없습니다.정상화는 당신의 친구이며 로켓 과학이 아닙니다.가입과 카디널리티는 상당히 단순한 개념입니다. 데이터베이스 애플리케이션 개발에 참여한다면 이해하지 못할 이유가 없습니다.

  1. 데이터베이스 스키마에서 버전 제어를 사용하지 않음
  2. 라이브 데이터베이스에 대해 직접 작업
  3. 고급 데이터베이스 개념(인덱스, 클러스터된 인덱스, 제약 조건, 구체화된 보기 등)을 읽고 이해하지 못함
  4. 확장성 테스트 실패... 단지 3~4개 행의 테스트 데이터만으로는 실제 실시간 성능의 실제 그림을 얻을 수 없습니다.

저장 프로시저에 대한 과도한 사용 및/또는 의존.

일부 애플리케이션 개발자들은 저장 프로시저를 중간 계층/프론트 엔드 코드의 직접적인 확장으로 보고 있습니다.이는 마이크로소프트 스택 개발자들의 공통적인 특성인 것으로 보이며(저도 그 중 하나이지만 이제는 더 이상 사용할 수 없게 되었습니다) 복잡한 비즈니스 로직과 워크플로우 처리를 수행하는 많은 저장 프로시저를 생성합니다.이것은 다른 곳에서 하는 것이 훨씬 낫습니다.

저장 프로시저는 어떤 실제 기술적 요소가 성능 및 보안과 같은 용도를 필요로 한다는 것이 실제로 입증된 경우에 유용합니다. 예를 들어, 대용량 데이터 세트의 집계/필터링을 "데이터에 가깝게" 유지하는 것입니다.

최근 비즈니스 로직 및 규칙의 70%가 1400개의 SQL Server 저장 프로시저(나머지는 UI 이벤트 핸들러)에 구현된 대규모 델파이 데스크톱 애플리케이션을 유지 및 개선해야 했습니다.이는 주로 TSQL에 효과적인 장치 테스트를 도입하기 어려웠으며 캡슐화 기능이 부족하고 툴(디버거, 편집기)이 열악했기 때문에 악몽과도 같았습니다.

과거에 Java 팀과 함께 작업하면서 종종 완전히 반대의 상황이 해당 환경에 존재한다는 사실을 빠르게 알게 되었습니다.자바 아키텍트는 "데이터베이스는 데이터를 위한 것이지 코드를 위한 것이 아니다"라고 말한 적이 있습니다.

요즘 저는 저장된 proc를 전혀 고려하지 않는 것이 실수라고 생각하지만, 유용한 이점을 제공하는 상황에서는 기본적으로 사용하지 않아야 합니다(다른 답변 참조).

1번 문제?그들은 장난감 데이터베이스에서만 시험을 합니다.따라서 데이터베이스가 커지면 SQL이 크롤링되어 나중에 누군가가 와서 수정해야 한다는 사실을 전혀 알지 못합니다(이 소리는 제 이를 가는 소리입니다).

인덱스를 사용하지 않습니다.

상관된 하위 쿼리로 인한 성능 저하

상관된 하위 쿼리를 피하기 위해 대부분의 경우.하위 쿼리 내에 외부 쿼리의 열에 대한 참조가 있는 경우 하위 쿼리는 상관 관계에 있습니다.이 경우 반환되는 각 행에 대해 최소 한 번 이상 서브쿼리가 실행되며 상관된 서브쿼리를 포함하는 조건이 적용된 후 다른 조건이 적용되면 더 많이 실행될 수 있습니다.

이러한 작위적인 예와 Oracle 구문은 용서하십시오. 하지만 마지막으로 해당 매장에서 하루에 1만 달러 미만의 매출을 올린 이후로 모든 직원을 고용하고 싶었다고 가정해 보겠습니다.

select e.first_name, e.last_name
from employee e
where e.start_date > 
        (select max(ds.transaction_date)
         from daily_sales ds
         where ds.store_id = e.store_id and
               ds.total < 10000)

이 예제의 하위 쿼리는 store_id에 의해 외부 쿼리와 연관되며 시스템의 모든 직원에 대해 실행됩니다.이 쿼리를 최적화할 수 있는 한 가지 방법은 하위 쿼리를 인라인 뷰로 이동하는 것입니다.

select e.first_name, e.last_name
from employee e,
     (select ds.store_id,
             max(s.transaction_date) transaction_date
      from daily_sales ds
      where ds.total < 10000
      group by s.store_id) dsx
where e.store_id = dsx.store_id and
      e.start_date > dsx.transaction_date

이 예제에서 from 절의 쿼리는 이제 인라인 뷰(일부 Oracle 특정 구문도 있음)가 되어 한 번만 실행됩니다.데이터 모델에 따라 이 쿼리는 훨씬 더 빨리 실행될 수 있습니다.직원 수가 증가함에 따라 첫 번째 쿼리보다 성능이 향상될 것입니다.직원이 거의 없고 많은 상점(그리고 아마도 많은 상점에 직원이 없을 수도 있음)이 있고 daily_sales 테이블이 store_id에 색인화되어 있다면 첫 번째 쿼리는 실제로 더 나은 성능을 발휘할 수 있습니다.이것은 가능성이 높은 시나리오는 아니지만 상관된 쿼리가 대안보다 더 나은 성능을 발휘할 수 있는 방법을 보여줍니다.

저는 후배 개발자들이 서브쿼리를 상관시키는 것을 여러 번 보아왔고, 그것은 대개 성능에 심각한 영향을 미쳤습니다.그러나 상관 관계가 있는 하위 쿼리를 제거할 때는 성능이 저하되지 않도록 설명 계획을 전후로 살펴야 합니다.

내 경험으로는:
숙련된 DBA와 소통하지 않음.

"실제" 데이터베이스 대신 접근 권한을 사용합니다.SQL Express, MySQLSQLite와 같이 훨씬 더 잘 작동하고 확장할 수 있는 작고 심지어 무료인 데이터베이스도 많이 있습니다.애플리케이션은 종종 예상치 못한 방식으로 확장해야 합니다.

테이블 간의 관계를 설정하는 것을 잊었습니다.저는 제가 지금의 고용주에서 일을 시작했을 때 이것을 치워야 했던 것을 기억합니다.

Excel을 사용하여 데이터를 저장(대량)합니다.

수천 개의 행을 보유하고 여러 워크시트를 사용하는 회사를 본 적이 있습니다(이전 버전의 Excel에서 행 제한이 65535이기 때문에).


Excel은 보고서, 데이터 프레젠테이션 및 기타 작업에 적합하지만 데이터베이스로 취급해서는 안 됩니다.

나는 다음과 같이 덧붙이고 싶습니다: 성능이 뛰어난 코드보다 "우아한" 코드를 선호합니다.데이터베이스에 대해 가장 잘 작동하는 코드는 애플리케이션 개발자의 눈에 거슬리는 경우가 많습니다.

조기 최적화에 대한 말도 안 되는 소리를 믿으면서 말입니다.데이터베이스는 원래 설계와 이후 개발 시 성능을 고려해야 합니다.성능은 데이터베이스 설계의 50%(데이터 무결성 40%, 보안 10%)라고 생각합니다.수행하기 위해 처음부터 구성되지 않은 데이터베이스는 실제 사용자와 실제 트래픽이 데이터베이스에 배치되면 성능이 저하됩니다.섣부른 최적화라고 해서 최적화가 불가능한 것은 아닙니다!이것이 더 쉽다는 것을 알기 때문에 거의 항상 성능이 떨어지는 코드를 작성해야 한다는 것을 의미하는 것은 아닙니다(예를 들어, 다른 모든 것이 실패하지 않는 한 프로덕션 데이터베이스에서는 절대 허용되지 않아야 하는 커서).즉, 필요할 때까지 마지막 남은 실적을 짜낼 필요가 없다는 뜻입니다.설계 및 개발에서 이를 무시하는 것은 기껏해야 근시안적인 일이기 때문에 데이터베이스에서 더 나은 성능을 발휘할 수 있는 것에 대해서는 많은 것이 알려져 있습니다.

매개 변수화된 쿼리를 사용하지 않습니다.SQL 주입을 막는데 아주 유용합니다.

다른 답변에 언급된 입력 데이터를 검사하지 않는 구체적인 예입니다.

나는 개발자가 중첩 선택 문을 사용하거나 심지어 함수를 사용하여 쿼리의 "SELECT" 부분 안에 있는 선택 문의 결과를 반환하는 것을 싫어합니다.

@adam과 비슷한 문제가 있음에도 불구하고 여기 다른 곳에서는 이것을 볼 수 없다는 것이 사실 놀랍습니다.

예:

SELECT
    (SELECT TOP 1 SomeValue FROM SomeTable WHERE SomeDate = c.Date ORDER BY SomeValue desc) As FirstVal
    ,(SELECT OtherValue FROM SomeOtherTable WHERE SomeOtherCriteria = c.Criteria) As SecondVal
FROM
    MyTable c

이 시나리오에서 MyTable이 10000 행을 반환하면 각 결과 행에 대해 초기 쿼리와 다른 테이블 각각에 대해 한 번씩 쿼리를 실행해야 했기 때문에 쿼리가 방금 20001 쿼리를 실행한 것과 같습니다.

개발자는 몇 행의 데이터만 반환하고 하위 테이블에는 대개 적은 양의 데이터만 저장되는 개발 환경에서는 이러한 작업을 수행할 수 있지만 프로덕션 환경에서는 테이블에 더 많은 데이터가 추가될수록 이러한 쿼리가 기하급수적으로 비용이 많이 들 수 있습니다.

(꼭 완벽하지는 않지만) 더 좋은 예는 다음과 같습니다.

SELECT
     s.SomeValue As FirstVal
    ,o.OtherValue As SecondVal
FROM
    MyTable c
    LEFT JOIN (
        SELECT SomeDate, MAX(SomeValue) as SomeValue
        FROM SomeTable 
        GROUP BY SomeDate
     ) s ON c.Date = s.SomeDate
    LEFT JOIN SomeOtherTable o ON c.Criteria = o.SomeOtherCriteria

이것은 데이터베이스 최적화자가 메인 테이블의 각 레코드에 있는 쿼리가 아니라 데이터를 함께 섞을 수 있게 해주며, 보통 이 문제가 발생한 코드를 수정해야 할 때 보통 쿼리 속도를 100% 이상 높이는 동시에 CPU와 메모리 사용량을 줄일 수 있습니다.

SQL 기반 데이터베이스의 경우:

  1. 클러스터된 인덱스를 활용하지 않거나 클러스터에 잘못된 열을 선택하지 않습니다.
  2. 상위/하위 테이블 관계에서 외부 키(INT)에 가입하기 위해 일련 번호(자동 번호) 데이터 유형을 기본 키로 사용하지 않습니다.
  3. 많은 레코드가 삽입되거나 삭제된 경우 테이블의 통계를 업데이트하지 않습니다.
  4. 많은 행이 삽입되거나 삭제된 경우 테이블을 재구성하지 않음(즉, 삭제 플래그가 있는 테이블에서 삭제된 행을 물리적으로 유지함).
  5. 트랜잭션 비율이 높은 대형 테이블에서 FRAMGATION ON EXPRANGETION(지원되는 경우)의 이점을 활용하지 않습니다.
  6. 열에 대한 데이터 유형을 잘못 선택합니다!
  7. 올바른 열 이름을 선택하지 않습니다.
  8. 테이블 끝에 새 열을 추가하지 않습니다.
  9. 자주 사용하는 쿼리를 지원하기 위한 적절한 인덱스를 만들지 않습니다.
  10. 가능한 값이 거의 없는 열에 인덱스를 만들고 불필요한 인덱스를 만듭니다.
    더 추가될 것입니다.
  • 운영 데이터베이스 내부의 문제를 해결하기 전에 백업을 수행하지 않습니다.

  • 저장 프로시저에서 저장된 객체(예: 테이블, 뷰)에 DDL 명령을 사용합니다.

  • 저장된 프로시저를 사용하는 것에 대한 두려움 또는 ORM 쿼리를 사용하는 것이 더 효율적이거나 적절한 장소에 사용하는 것에 대한 두려움.

  • 데이터베이스 프로파일러의 사용을 무시합니다. 데이터베이스 프로파일러는 ORM 쿼리가 최종적으로 무엇으로 변환되는지를 정확하게 알려주기 때문에 ORM을 사용하지 않을 때 로직을 확인하거나 디버깅을 위해 사용할 수 있습니다.

올바른 수준의 정규화 작업을 수행하지 않습니다.데이터가 중복되지 않도록 하고 필요에 따라 데이터를 여러 개로 분할하려고 합니다.또한 성능을 저하시킬 수 있으므로 정규화를 너무 많이 따르지 않는지 확인해야 합니다.

데이터베이스를 단순한 저장 메커니즘(예: 미화된 컬렉션 라이브러리)으로 취급하여 애플리케이션에 종속(데이터를 공유하는 다른 애플리케이션 무시)

  • "너무 마법적이다" 또는 "내 데이터베이스에 없다"와 같은 이유로 Hibernate와 같은 ORM을 손에서 놓지 않는 것.
  • Hibernate와 같은 ORM에 너무 많이 의존하고 적절하지 않은 곳에서 신발을 신으려고 노력하는 것.

1 - where 절의 값에 해당 인덱스를 사용하지 않는 결과 값에 함수를 불필요하게 사용합니다.

예:

where to_char(someDate,'YYYYMMDD') between :fromDate and :toDate

대신에

where someDate >= to_date(:fromDate,'YYYYMMDD') and someDate < to_date(:toDate,'YYYYMMDD')+1

그리고 더 적은 범위로:함수 인덱스가 필요한 값에 함수 인덱스를 추가하지 않는 중...

2 - 데이터의 유효성을 보장하기 위해 검사 제약 조건을 추가하지 않습니다.제약 조건은 쿼리 최적화기에서 사용할 수 있으며 불변량을 신뢰할 수 있도록 보장하는 데 정말 도움이 됩니다.그것들을 사용하지 않을 이유가 없습니다.

3 - 순수한 게으름이나 시간의 압박으로 테이블에 정규화되지 않은 열을 추가합니다.사물들은 대개 이런 방식으로 설계되지 않지만, 이것으로 진화합니다.결국 미래의 진화 과정에서 손실된 데이터 무결성에 영향을 받았을 때 이를 해결하기 위해 엄청난 노력을 기울이는 것입니다.

데이터가 없는 테이블을 다시 디자인하는 것이 매우 저렴하다고 생각해 보세요.몇 백만개의 기록이 있는 테이블에 청렴도가 없는...다시 디자인하기에는 그리 저렴하지 않습니다.따라서 열이나 표를 작성할 때 올바른 설계를 수행하면 스페이드로 상각됩니다.

4 - 데이터베이스 자체에 대한 것은 아니지만 정말 짜증납니다.SQL의 코드 품질은 신경쓰지 않습니다.SQL이 텍스트로 표현된다는 사실만으로 문자열 조작 알고리즘에 논리를 숨겨도 되는 것은 아닙니다.동료 프로그래머가 실제로 읽을 수 있는 방식으로 텍스트로 SQL을 작성하는 것은 완벽하게 가능합니다.

이것은 이전에도 말했지만, 인덱스, 인덱스.프로파일링을 조금만 하면(어떤 테이블이 많이 타격을 받는지 확인하기 위해) 해당 테이블에 인덱스를 추가하는 것만으로 해결되는 엔터프라이즈 웹 앱을 제대로 수행하지 못하는 사례를 많이 보았습니다.이를 위해서는 SQL이 지식을 작성하는 방식으로도 많은 것이 필요하지 않으며, 그 대가는 엄청납니다.

페스트와 같은 데이터 중복을 방지합니다.일부 사람들은 복제를 조금만 해도 문제가 되지 않으며 성능이 향상될 것이라고 주장합니다.스키마가 너무 추상적이어서 DBA도 상황을 모를 때까지 스키마를 써드 노멀 폼으로 고문해야 한다는 말이 아닙니다.이름, 우편번호 또는 배송 코드를 복제할 때마다 복사본이 서로 동기화되지 않게 됩니다.그렇게 될 겁니다.그리고는 주간 유지보수 스크립트를 실행하면서 스스로 발로 차게 될 것입니다.

그리고 마지막으로, 명확하고 일관되고 직관적인 명명 규칙을 사용합니다.잘 작성된 코드 조각을 읽어야 하는 것과 마찬가지로, 좋은 SQL 스키마 또는 쿼리를 읽을 수 있어야 하며 주석 없이도 실제로 수행 중인 작업을 알려주어야 합니다.6개월 안에 테이블을 정비해야 할 때 스스로에게 감사하게 될 것입니다."SELECT account_number, billing_date FROM national_accounts".SELECT ACCNTNBR, BILLDAT FROM NTNLACTS"보다 훨씬 쉽게 작업할 수 있습니다.

DELETE 쿼리를 실행하기 전에(특히 프로덕션 데이터베이스에서) 해당 SELECT 쿼리를 실행하지 않음!

20년 동안 내가 본 가장 흔한 실수는 미리 계획하지 않는 것입니다.많은 개발자들이 데이터베이스와 테이블을 만든 다음, 응용프로그램을 구축할 때 테이블을 계속 수정하고 확장합니다.최종 결과는 종종 엉망이고 비효율적이며 나중에 정리하거나 단순화하기가 어렵습니다.

a) 쿼리 값을 문자열로 하드코딩
b) Windows Forms 응용프로그램의 "OnButtonPress" 수행에 데이터베이스 쿼리 코드 넣기

둘 다 봤어요.

응용프로그램에서 데이터베이스 연결 관리에 충분한 주의를 기울이지 않습니다.그러면 응용 프로그램, 컴퓨터, 서버, 네트워크가 막혔다는 것을 알게 됩니다.

  1. DBA 및 데이터 모델/디자이너라고 생각할 때, 해당 분야에 대한 공식적인 가르침이 전혀 없습니다.

  2. 프로젝트가 단순하기 때문에 DBA가 필요 없다고 생각합니다.

  3. 데이터베이스에서 수행해야 할 작업과 앱에서 수행해야 할 작업을 적절히 구분하지 못함

  4. 백업의 유효성을 검사하지 않거나 백업하지 않습니다.

  5. 코드에 원시 SQL을 포함합니다.

Scott Walz의 '고전 데이터베이스 개발 실수와 를 극복하는 5가지 방법'이라는 동영상 링크를 소개합니다.

데이터베이스 동시성 모델과 이것이 개발에 어떤 영향을 미치는지에 대한 이해가 없습니다.인덱스를 추가하고 사후에 쿼리를 조정하는 것은 쉽습니다.그러나 핫스팟, 리소스 경합 및 올바른 작동에 대한 적절한 고려 없이 설계된 애플리케이션(방금 읽은 내용이 여전히 유효하다고 가정!)은 나중에 수정하려면 데이터베이스 및 애플리케이션 계층 내에서 상당한 변경이 필요할 수 있습니다.

DBMS가 후드 아래에서 어떻게 작동하는지 이해하지 못합니다.

클러치가 어떻게 작동하는지 이해하지 못하면 스틱을 제대로 구동할 수 없습니다.그리고 실제로 하드 디스크의 파일에 쓰기만 한다는 것을 이해하지 못하면 데이터베이스 사용 방법을 이해할 수 없습니다.

구체적으로:

  1. Clustered Index란 무엇인지 알고 계십니까?스키마를 설계할 때 생각해 보셨나요?

  2. 인덱스를 적절하게 사용하는 방법을 알고 있습니까?인덱스를 재사용하는 방법은?커버링 인덱스(Covering Index)가 무엇인지 아나요?

  3. 정말 대단하네요, 지수가 있네요.당신의 색인에서 한 줄은 얼마나 큰가요?데이터가 많을 때 지수는 얼마나 클까요?기억에 잘 맞을까요?그렇지 않다면 지표로서 쓸모가 없습니다.

  4. MySQL에서 EXPLAINE을 사용해 본 적이 있습니까?좋아요.이제 자신에게 솔직해지세요.당신이 본 것의 반이라도 이해했나요?아니요, 아마 안 했을 겁니다.고쳐주세요.

  5. 쿼리 캐시를 이해하십니까?무엇이 쿼리를 연결할 수 없게 만드는지 아나요?

  6. 마이 아이샘을 사용하고 있습니까?전문적인 검색이 필요하다면, 어쨌든 내 ISAM은 엉망진창입니다.스핑크스를 사용합니다.그럼 Inno로 바꿉니다.

  1. ORM을 사용하여 대량 업데이트 수행
  2. 필요 이상의 데이터를 선택합니다.다시 말하지만, 일반적으로 ORM을 사용할 때 수행됩니다.
  3. sqls를 고리로 발사합니다.
  4. 테스트 데이터가 좋지 않고 실시간 데이터에서만 성능 저하를 감지할 수 있습니다.

언급URL : https://stackoverflow.com/questions/621884/database-development-mistakes-made-by-application-developers

반응형