왜 코드가 아닌 데이터베이스에 제약 조건이 적용됩니까?


21

데이터베이스에 제약이 적용되는 이유는 무엇입니까? 코드에 넣는 것이 더 유연하지 않습니까?

데이터베이스 구현에 대한 초보자 책을 읽고 있으므로 초보자로 요구하고 있습니다. 이 엔티티 모델을 포함하여 데이터베이스를 설계했다고 가정 해 보겠습니다.

 entity type    |   sub-types
----------------+--------------------------------------------
   Person       |   Employee, Student,       ...
   Student      |   Graduate, Undergraduate, ...
   Employee     |   Teacher,  Administrator, ...

현재 제약 사항 :

  1. 시스템에 등록 된 사람은 학생 또는 직원 만 될 수 있습니다.
  2. 개인 실체는 사회 번호의 고유성을 필요로하며, 우리는 모든 사람이 하나의 고유 한 개체 (일명 충분한 기본 키) 만 가지고 있다고 가정합니다 . (# 1 참조)

나중에 우리는 숫자 1을 제거하기로 결정합니다. 언젠가 대학에서 Teacher( Employee하위 유형)도 Student자유 시간에 코스를 수강 한다고 결정하면 수천, 수백만, 수십억을 가질 수있는 데이터베이스 디자인을 변경하는 것이 훨씬 어렵습니다. 코드의 논리를 변경하기보다는 수십억의 항목 : 학생과 직원으로 사람을 등록 할 수없는 부분.

(그것은 매우 불가능하지만 지금은 다른 것을 생각할 수 없습니다. 분명히 가능합니다).

왜 코드가 아닌 데이터베이스 디자인 에서 비즈니스 규칙에 관심이 있습니까?

# 1 : 7 년 후의 메모, 실제 사례 :
저는 실수로 인해 발행 된 SSN이 여러 사람인 동일한 SSN과 중복되는 정부를 보았습니다. 원래 DB를 설계하는 사람들은 데이터베이스에서이 고유 제한 조건을 적용하지 않는 실수를 저질렀습니다. (그리고 나중에 원래 응용 프로그램의 버그-공유 데이터베이스를 사용하고 제약 조건을 배치, 확인 및 시행 할 위치에 동의하지 않는 여러 응용 프로그램? ...).
이 버그는 시스템 그 이후에 개발 된 모든 시스템에서 계속 살아남을 것이며, 이후 수년 동안 원래 시스템의 데이터베이스에 의존합니다. 여기에서 답을 읽으면서 가능한 한 많은 실제 제약 조건을 데이터베이스에 현명하게 (맹목적으로는 아님) 가능한 모든 제약 조건에 적용하는 방법을 배웠습니다.


2
우리는 대부분 비즈니스 규칙을 시행하고이를위한 최선의 방법에 관심을 갖습니다.
ypercubeᵀᴹ

3
엔터티의 유연성과 데이터베이스의 확장 성은 대부분 정규화에 의해 정의되므로 실제로 어떤 제약 조건이 사용되는지에 대한 매우 나쁜 예를 제시하고 있습니다. 그럼에도 불구하고 제약 조건은 새로운 응용 프로그램이 개발 되더라도 외부 API를 추가하더라도 누군가가 직접 DB를 편집하더라도 응용 프로그램에 버그가 발생하더라도 데이터베이스에 들어오는 모든 손상된 데이터에 대한 최종 보호 수단입니다. 제약 조건은 데이터베이스를 보호하는데, 그 외에도 비즈니스 로직은 DB에 액세스하기 전에 자체 작업을 수행해야합니다.
Niels Keurentjes

3
실제로 대학원생으로서 저는 학생, 직원 및 교사로 간주됩니다. 따라서 귀하의 예는 실제로 불가능하지 않습니다.
Winston Ewert

4
응용 프로그램의 개체를 기반으로 데이터베이스 디자인을 작성해서는 안됩니다. 이것을 노 멀리로 사람으로 디자인 한 다음 사람의 역할을 정의하는 관련 테이블을 갖습니다. sso 사람들이 여러 역할을 수행 할 수있는 역할에 대한 인식 된 표가 있으면 문제가 발생하지 않습니다. 역할 담당자가 하나만 있으면 peopleID가 고유하도록 테이블을 제한합니다. 제한을 제거하려면 변경하십시오.
HLGEM

객체 <-> 관계형 매핑은 예술입니다.
Thorbjørn Ravn Andersen

답변:


34

일부 제약 조건은 데이터베이스에서 가장 잘 적용되고 일부 제약 조건은 응용 프로그램에서 가장 잘 적용됩니다.

데이터베이스에 가장 잘 적용되는 제약 조건은 일반적으로 제품이 유효한지 확인하기위한 외래 키 제약 조건과 같은 데이터 모델 구조의 기본이기 때문에 존재합니다 category_id.

응용 프로그램에 적용되는 제약 조건은 모든 FooBar 제품과 같이 데이터 모델에 기본이 아닐 수 있습니다. 그러나 나중에 누군가 FooBars가 노란색 일 수 있다고 결정할 수도 있습니다. 이것은 별도의 colours테이블을 생성 할 수 있고 데이터베이스가 제품이 해당 테이블의 유효한 항목을 참조하도록 요구할 수 있지만 실제로는 데이터베이스에있을 필요는없는 응용 프로그램 논리입니다 . 그러나 유일한 레코드에 colours가치 blue가 있다는 결정 은 여전히 데이터베이스 외부 어딘가에서 나올 것 입니다.

데이터베이스에 제한 조건이없고 응용 프로그램에 모두 적용되도록 요구하면 어떤 일이 발생하는지 고려하십시오. 데이터 작업에 필요한 응용 프로그램이 둘 이상있는 경우 어떻게됩니까? 다른 응용 프로그램이 제약 조건을 다르게 적용하기로 결정한 경우 데이터는 어떻게 표시됩니까?

귀하의 예는 데이터베이스가 아닌 애플리케이션에서 제약 조건을 갖는 것이 더 유리한 상황을 보여 주지만 초기 데이터 모델이 너무 제한적이고 융통성이 없다는 근본적인 문제가 있었습니까?


따라서이 답변에 따르면 <사람은 학생의 하위 유형 테이블에만 존재하거나 직원 하위 유형 테이블에만 존재할 수 있음> 규칙을 코드에 적용해야하며 데이터베이스에는 <학생 / 직원 하위 유형이 유효해야합니다. 사람> 제약. 내가 맞아? (책의 예였습니다). 감사.
hkoosha

2
@loolooyyyy : 예, 맞습니다. 데이터베이스 (사람이 할 수있는 첫 번째 규칙을 적용하는 경우 에만 때문에 다음 (직원이 클래스에 등록하고자하는) 당신이 설명하는 상황이 불가능 학생이나 직원 수) : 사람이 모두를 할 수 없으며, 그렇지 않아 그들은 아마도 정부와 같은 제 3 자로부터 발행 된 사회 보장 번호를 공유 할 수 없기 때문에 두 번째 "개인"레코드를 만들 수도 있습니다. 물론이 지나치게 제한적인 데이터 모델은 어떤 경우에는 작동 할 수 있습니다.
FrustratedWithFormsDesigner

2
@loolooyyyy : 원본 데이터 모델을 사용하고 교사가 학생이되도록하는 또 다른 방법 teachers_as_students은 또 다른 하위 유형 인 라는 또 다른 테이블 이 Students있고을 참조하는 새로운 외래 키 Teachers와 소셜 대신 시스템 생성 기본 키를 갖는 것입니다. 보안 번호. 이런 식으로, "학생"은 실제로 교사의 별명이므로 교사는 여전히 수업에 등록 할 수 있습니다. 전체 데이터 모델을 보지 않고도 이것이 얼마나 잘 작동하는지 확실히 말하기는 어렵습니다.
FrustratedWithFormsDesigner

2
나는 이것을 하향 투표했다. 응용 프로그램 에서만 제약 조건이 가장 잘 적용되는 시간은 없습니다 . 이 답변의 톤이 잘못 가중되었습니다.
Evan Carroll

3
확실히 @FrustratedWithFormsDesigner는 실제로 외래 키 제약 조건의 포스터 자식입니다. 서로 다른 버전 / 빌드의 DB 액세스 포인트 클라이언트가 있다고 가정 해 봅시다. 빨간색으로 제품 배송을 중단하면 어떻게해야합니까? 가능한 색상 조합 목록을 어디에 저장 하시겠습니까? 힌트 : 중앙 집중식 장소가 있습니다. 테이블을 만들 수 있다면 color_products, 그리고 colorfkeys 다음과 같은 대부분의 IDE / 스키마 로더, 지원 - 당신은 가능성이 더 쉽게 추가 드롭 다운을 만들 수 있습니다.
Evan Carroll

35

때문에:

  1. 내가 원하는 모든 데이터베이스의 데이터가 동일한 제약의 대상이 될뿐 아니라 새로운 데이터가 현재 실행중인 코드의 버전 제약의 대상이 될 수 있습니다.
  2. 프로그래밍 제약이 아닌 선언적 제약을 원합니다.
  3. 데이터베이스의 데이터는 종종 오늘날의 데이터베이스와 상호 작용하도록 작성된 코드보다 오래 지속됩니다. 그리고 코드가 아닌 해당 데이터는 조직의 자산입니다.
  4. 모든 데이터가 엄격한 제약을 받는다는 것을 알면 코드가 훨씬 간단 해집니다. 더 이상 데이터베이스가 불가능하다는 것을 알고있는 특별한 경우를 고려할 필요가 없습니다.

나에게 중요한 몇 가지 이유.


4
(1) 및 (3)과 반-관련 : 응용 프로그램 코드의 버그를 수정할 수 있으며 데이터의 버그를 복구 할 수없는 경우가 많습니다.
mu는

17

데이터는 애플리케이션 코드보다 오래 지속될 것입니다. 규칙이 데이터의 무결성을 유지하는 데 도움이되는 외래 키 제약 조건과 같이 시간이 지남에 따라 유용한 데이터에 중요한 경우 규칙이 데이터베이스에 있어야합니다. 그렇지 않으면 데이터베이스에 충돌하는 새 응용 프로그램에서 제약 조건을 잃을 위험이 있습니다. 여러 응용 프로그램이 데이터베이스에 영향을 줄뿐만 아니라 (중요한 데이터 규칙이 있음을 인식하지 못하는 응용 프로그램 포함) 데이터 가져 오기 또는보고 응용 프로그램과 같은 일부 응용 프로그램은 기본 데이터 입력 응용 프로그램에서 설정된 데이터 계층을 사용하지 못할 수 있습니다. 솔직히, 제약 조건에 버그가있을 가능성은 내 경험에 따라 응용 프로그램 코드에서 훨씬 높습니다.

내 개인적인 견해로는 (30 년 이상 데이터를 다루고 수백 가지의 다른 데이터베이스를 사용한 많은 다른 목적에 대한 경험을 바탕으로) 그들이 속한 데이터베이스에 제약을 두지 않는 사람은 결국 데이터가 좋지 않습니다. 때로 나쁜 데이터는 사용할 수없는 수준이됩니다. 감사에 대한 특정 기준을 충족해야하는 재무 / 규제 데이터가있는 경우 특히 그렇습니다.


17

데이터베이스 외부에서 구현되는 대부분의 참조 무결성 제약 조건을 무시할 수 있으므로 데이터 무결성을 항상 보장하려면 데이터베이스에 제약 조건을 적용해야합니다. 그만해.

일반적으로 데이터베이스 읽기 일관성 메커니즘을 통해 응용 프로그램 수준 제약 조건을 무시합니다.이를 통해 세션은 커밋 될 때까지 다른 세션의 데이터를 볼 수 없습니다.

예를 들어 두 세션에서 고유 한 열에 동일한 값을 삽입하려고 할 수 있습니다. 값이 아직 존재하지 않는지 동시에 확인할 수 있고 값을 삽입 할 수 있으며 커밋 할 수 있습니다. 데이터베이스에 구현 된 고유 제한 조건으로 인해 이러한 상황이 발생하지 않습니다.

그건 그렇고, 응용 프로그램 언어 디자이너에게는 알려지지 않았습니다. Ruby on Rails 안내서 : 활성 레코드 유효성 검증 및 콜백 에서 섹션 3.10 고유성 을 읽으십시오 .

이 헬퍼는 객체가 저장되기 직전에 속성 값이 고유한지 확인합니다. 데이터베이스에서 고유성 제한 조건을 작성하지 않으므로 서로 다른 두 개의 데이터베이스 연결이 고유 한 컬럼에 대해 동일한 값을 가진 두 개의 레코드를 작성합니다. 이를 방지하려면 데이터베이스에서 고유 색인을 작성해야합니다.


16

데이터베이스에 의해 시행되는 제약의 장점 :

단순성 -제약 조건 선언은 제약 조건을 선언하고 해당 선언을 시행 할 코드를 작성하는 것보다 훨씬 간단합니다.

정확성 -작성하지 않은 코드에는 사용자가 만든 버그가 없습니다. 데이터베이스 공급 업체는 제약 조건 코드가 정확한지 확인하는 데 시간을 소비하므로 그럴 필요가 없습니다.

속도 -응용 프로그램이 기반 데이터베이스보다 더 많은 배포를 가질 수 없습니다. 데이터베이스 공급 업체는 제약 조건 코드의 효율성을 확인하는 데 시간을 소비하므로 그럴 필요가 없습니다. 데이터베이스 자체는 응용 프로그램이 아무리 효율적이더라도 데이터에 빠르게 액세스 할 수 있습니다.

재사용- 하나의 플랫폼에서 하나의 응용 프로그램으로 시작할 수 있지만 그대로 유지되지 않을 수 있습니다. 다른 OS, 다른 하드웨어 또는 음성 인터페이스에서 데이터에 액세스해야하는 경우 어떻게합니까? 데이터베이스에 제약 조건을 가짐으로써이 코드를 새 플랫폼에 대해 다시 작성할 필요가 없으며 정확성을 위해 디버깅하거나 속도를 프로파일 링 할 필요가 없습니다.

완전성 -응용 프로그램은 데이터가 데이터베이스에 입력 될 때 제약 조건을 적용하며 이전 데이터가 정확한지 확인하거나 데이터베이스에 이미있는 데이터를 조작하려면 추가 노력이 필요합니다.

수명 -데이터베이스 플랫폼이 특정 애플리케이션보다 오래 지속될 수 있습니다.


11

서버에 제약 조건이 적용되는 이유는 무엇입니까? 나쁜 사람들이 당신의 클라이언트를 사용하도록 강요 할 수 없기 때문입니다.

명확히하기 위해 클라이언트 응용 프로그램에서 비즈니스 규칙 처리 만 수행하는 경우 다른 도구를 사용하는 사람이 데이터베이스 규칙에 연결하여 비즈니스 규칙 및 무결성 검사에 의해 제약을받지 않고 원하는 작업을 수행 할 수 있습니다. 네트워크의 어느 곳에서나 임의의 도구를 사용하지 못하게하는 것은 매우 어렵습니다.

데이터베이스 서버에서 무결성 검사를 수행하면 도구에 관계없이 데이터에 액세스하려는 모든 시도가 규칙에 의해 제한됩니다.


10

여기에 큰 대답이 있으며 다른 생각을 반복 할 위험이 있습니다.

  • SSN이 반드시 고유 하지는 않습니다 . SSN은 항상 알려진 것은 아니며 어떤 경우에는 아직 존재하지 않습니다. SSN을 재사용 할 수 있으며 모든 직원이나 학생에게 SSN이있는 것은 아닙니다. 이것은 문제의 주변에 있지만 제약 조건을 적용하는 위치에 관계없이 비즈니스 규칙에 대한 결정을 내리려면 데이터 모델과 도메인을 완전히 이해해야한다는 것을 보여줍니다.
  • 개인적으로 나는 제약이 가능한 한 데이터에 가깝도록 선호합니다. 매우 간단한 이유는 모든 사람이 응용 프로그램 코드를 사용하여 데이터베이스의 데이터를 변경하지는 않기 때문입니다. 애플리케이션 레벨에서 비즈니스 규칙을 시행 UPDATE하고 데이터베이스에 대해 직접 명령문을 실행하는 경우 애플리케이션이 유효하지 않은 변경을 어떻게 방지합니까? 앱에서 비즈니스 규칙의 또 다른 문제는 재 컴파일 / 재배포가 어려울 수 있다는 것입니다. 특히 모든 사람이 동시에 업데이트를받을 수있는 것은 아닌 분산 앱의 경우 더욱 그렇습니다. 마지막으로, 애플리케이션에서 비즈니스 규칙을 변경하면 새로운 규칙을 위반하는 기존 데이터에 대해 전혀 아무 것도 수행하지 않습니다. 데이터에 새 제한 조건을 추가하는 경우 데이터를 수정해야합니다.
  • 여러 수준에서 여러 중복 검사를 정당화 할 수 있습니다. 이는 배포 방법론의 유연성, 변경 가능성 및 데이터베이스 및 기타 계층에서 비즈니스 규칙 변경을 동기화하는 것이 얼마나 어려운지에 달려 있습니다. 앱 계층에서 검사를 반복해야한다는 강력한 주장은 제약 조건의 특성과 기존 데이터에 의존하는지 여부에 따라 데이터베이스에 대한 왕복이 제약 조건에 실패하는 것만 막을 수 있다는 것입니다. 그러나 하나 또는 다른 것을 선택 해야하는 경우 위의 이유로 데이터베이스에 넣었습니다.

명시 적으로 언급 한 경우, 이전에 허용되지 않은 것을 갑자기 허용하는 경우 이는 실제로 문제가되지 않습니다. 존재하는 위치에 상관없이 강제로 적용되는 모든 제한을 제거합니다. 반대로 교사가 더 이상 학생이 될 수없는 경우에는 이전에 제약 조건이 있던 위치에 관계없이 정리할 데이터가 많이있을 수 있습니다.


9
  1. 데이터베이스는 제약 조건을 효과적으로 확인할 수 있습니다. 코드보다 낫다.

  2. 무결성 제약 조건은 데이터베이스가 효과적인 실행 계획을 찾는 데 도움이됩니다.

  3. 응용 프로그램은 읽기 일관성있는보기를 보므로 고유성을 거의 보장 할 수 없습니다. 데이터베이스는 커밋되지 않은 데이터도 볼 수 있습니다.


8

짧은 답변 ... 데이터 무결성 (예 : 정확성 및 유효성)을 보존합니다.

예외 ...
데이터베이스가 대부분의 Sqlite 데이터베이스와 같이 단일 사용자에 대한 단일 응용 프로그램의 데이터를 저장하는 경우 제약 조건이 필요하지 않을 수 있습니다. 실제로, 그들은 액세스 시간을 너무 빨리 측정하기 위해 측정 할 수없는 경우가 많지 않습니다.

그 밖의 모든 것에는 ...
데이터베이스는 항상 편집자사용자 라고하는 두 개의 마스터를 제공 합니다 .

편집자는 대부분 데이터를 데이터베이스에 저장하고 한 번에 하나 또는 적은 수의 레코드를 검색합니다. 주요 관심사는 모든 관련 데이터에 빠르고 정확하게 액세스하고 변경 사항을 빠르고 안정적으로 저장하는 것입니다.

사용자는 대부분 데이터를 검색하며 의심 할 여지없이 정확한 정보에 빠르게 액세스하는 데 가장 관심이 있습니다. 그들은 종종 녹색 막대 종이 인쇄물의 상징적 인 발 두께 스택에서 생성되던 다양한 수, 집계 및 목록이 필요하지만 일반적으로 오늘날 웹 페이지에 나타납니다.

데이터베이스 개발 프로젝트는 거의 항상 사용자 의 요청에 따라 시작 되지만 디자인은 데이터 입력 및 한 번에 한 번의 편집자 요구에 의해 주도됩니다 . 따라서 경험이 부족한 개발자는 종종 데이터베이스에 제약 조건을 두지 않음으로써 (주로 개발의 ) 속도에 대한 즉각적인 요구에 응답 합니다.

경우 오직 하나의 응용 프로그램이 이제까지의 데이터를 변경하기 위해 사용되는 것입니다 인생 전체 데이터베이스를, 그리고 응용 프로그램이 하나 잘 조화 개인의 소수에 의해 개발되고, 에 의존하는 것이 합리적 일 데이터 무결성을 보장하는 애플리케이션.

그러나 미래를 예측할 수있는 척할 수는 없습니다.

데이터베이스를 생성하려는 노력은 너무 귀중하여 데이터베이스를 버릴 수 없습니다. 집처럼 데이터베이스는 여러 번 확장, 변경 및 개조됩니다. 완전히 교체 되더라도 모든 이전 비즈니스 규칙과 관계를 유지하면서 모든 데이터가 새 데이터베이스로 마이그레이션됩니다.

제약 조건은 이러한 규칙과 관계를 데이터베이스 엔진 자체에서 쉽게 액세스 할 수있는 간결하고 선언적인 형식으로 구현합니다. 이들이 없으면 후속 개발자는 이러한 규칙을 역 엔지니어링하기 위해 응용 프로그램을 따라야합니다. 행운을 빕니다!

이것은 관계형 엔진과 제약 조건이 있기 전에 대규모 데이터베이스를 만들었 기 때문에 메인 프레임 COBOL 프로그래머가해야 할 일입니다. IBM의 DB2와 같은 최신 시스템으로 마이그레이션하더라도 일련의 COBOL "일괄 처리"프로그램으로 구현 된 이전 규칙의 논리가 변환하기에 실용적이지 않을 정도로 복잡하기 때문에 제한 조건이 완전히 구현되지 않는 경우가 있습니다. 자동화 된 툴을 사용하여 기존 COBOL을 새로운 관계형 엔진에 대한 인터페이스와 약간의 조정만으로도 데이터 무결성이 보존됩니다. 새로운 앱이 작성 될 때까지 모든 것이 미묘하게 손상되고 회사가 운송 될 때까지 기존 COBOL을 최신 버전으로 변환 할 수 있습니다. 예를 들어, 자신이 가져서는 안되는 수천 명의 주택 소유자를 예고하기 위해 법정으로.


7

다른 의견 외에도 ...

주어진 테이블을 하나 이상의 응용 프로그램이나 코드 경로로 업데이트 할 수있는 데이터베이스가있는 경우 데이터베이스에 적절한 제약 조건을 적용하면 응용 프로그램이 "동일한"제약 조건 코드를 복제하지 않습니다. 이는 유지 보수를 단순화하고 (데이터 모델 변경이있는 경우 / 변경할 장소 수를 줄임) 데이터를 업데이트하는 응용 프로그램에 관계없이 구속 조건이 일관되게 적용되도록함으로써 이점을 제공합니다.


5

개인적으로 소스 코드를 사용하여 비즈니스 규칙을 시행하는 한 가지 방법 인 트리거를 만드는 것보다 제약 조건을 만들고 변경하는 것이 더 쉽다고 생각합니다.

또한 트리거는 일반적으로 PL / SQL과 같은 공급 업체별 언어로 작성되므로 이식성이 떨어집니다.

그러나 제약 조건이 요구 사항을 충족하지 않으면 항상 트리거를 사용하여 비즈니스 규칙을 시행 할 수 있습니다.


5
또한 읽기 일관성 문제로 인해 트리거가 무결성을 보장하지 않습니다.
David Aldridge

3

항상 데이터베이스에 먼저 적용해야합니다 .

  1. 데이터베이스는 서로 다른 클라이언트간에 무결성을 보장합니다. 다른 플랫폼의 다른 클라이언트가 데이터베이스에 액세스하도록 할 수 있습니다. 데이터베이스의 제약 조건으로 인해 새 클라이언트를 만들 때 무결성 문제가 발생할 위험이 없습니다. 이를 통해 재 작성 또는 추가 액세스 포인트 발생시 제약 조건을 Q / A 할 필요가 없습니다.
  2. 데이터베이스에는 제약 조건을 구축하기위한 DSL이 있습니다. SQL DDL!
  3. 데이터베이스는 시스템 카탈로그에서 해당 제한 조건에 대한 액세스를 제공하므로 적절한 ORM 또는 "스키마 로더" 가 해당 제한 조건을 읽고이를 응용 프로그램으로 가져올 수 있습니다. 예를 들어, 데이터베이스에 varchar(5)유형 이 있다고 지정 하면 언어 유형을 스키마 유형에 맵핑하고 크기에 대한 자체 제한 조건을 조합하는 특정 언어에 대한 스키마로드 ORM을 찾을 수 있습니다. DBIx for Perl is one such schema loader; 여기 Entity Framework의 또 다른 내용이 있습니다. 이러한 로더의 기능은 다양하지만, 제공 할 수있는 것은 데이터베이스로 이동하지 않고도 앱의 무결성을 보장하기위한 좋은 시작입니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.