200 줄 길이의 함수로 애플리케이션을 작성하지 않을 것입니다. 이러한 긴 함수를 각각 명확하게 정의 된 단일 책임을 가진 더 작은 함수로 분해합니다.
왜 그렇게 SQL을 작성합니까?
함수를 분해하는 것처럼 쿼리 를 분해합니다. 이를 통해 더 짧고, 더 간단하고, 이해 하기 쉽고 , 테스트 하기 쉽고, 리팩토링하기가 더 쉽습니다. 그리고 절차 적 코드에서와 같이 그들 사이에 "심"과 "래퍼"를 추가 할 수 있습니다.
어떻게하나요? 쿼리가 수행하는 각 중요한 작업을 뷰로 만듭니다. 그럼 당신은 구성 이 더 원시적 인 기능에서 더 많은 복잡한 기능을 구성하는 것처럼,이 간단한 뷰에서 더 많은 복잡한 쿼리를.
그리고 가장 좋은 점은 대부분 의 뷰 구성에서 RDBMS에서 정확히 동일한 성능을 얻을 수 있다는 것입니다. (일부는 그렇게하지 않을 것입니다. 그래서 어떻습니까? 조기 최적화는 모든 악의 근원입니다. 먼저 올바르게 코딩 한 다음 필요한 경우 최적화하십시오.)
다음은 복잡한 쿼리를 분해하기 위해 여러보기를 사용하는 예입니다.
이 예에서는 각보기가 하나의 변환 만 추가하므로 각보기를 독립적으로 테스트하여 오류를 찾을 수 있으며 테스트는 간단합니다.
예제의 기본 테이블은 다음과 같습니다.
create table month_value(
eid int not null, month int, year int, value int );
이 테이블은 절대 월인 하나의 기준을 나타 내기 위해 월과 연도의 두 열을 사용하기 때문에 결함이 있습니다. 새로운 계산 열에 대한 사양은 다음과 같습니다.
선형 변환으로 수행하여 (연도, 월)과 동일하게 정렬하고 임의의 (연도, 월) 튜플에 대해 하나의 값만 있고 모든 값이 연속되도록합니다.
create view cm_absolute_month as
select *, year * 12 + month as absolute_month from month_value;
이제 테스트해야하는 것은 사양에 내재되어 있습니다. 즉, 모든 튜플 (연도, 월)에 대해 하나 (absolute_month) 만 있고 그 (absolute_month)는 연속적이라는 것입니다. 몇 가지 테스트를 작성해 봅시다.
테스트는 select
테스트 이름과 케이스 문이 함께 연결된 구조 의 SQL 쿼리입니다. 테스트 이름은 임의의 문자열입니다. 케이스 진술은 단지 case when
테스트 진술 then 'passed' else 'failed' end
입니다.
테스트 문은 테스트를 통과하기 위해 참이어야하는 SQL 선택 (서브 쿼리) 일뿐입니다.
다음은 첫 번째 테스트입니다.
--a select statement that catenates the test name and the case statement
select concat(
-- the test name
'For every (year, month) there is one and only one (absolute_month): ',
-- the case statement
case when
-- one or more subqueries
-- in this case, an expected value and an actual value
-- that must be equal for the test to pass
( select count(distinct year, month) from month_value)
--expected value,
= ( select count(distinct absolute_month) from cm_absolute_month)
-- actual value
-- the then and else branches of the case statement
then 'passed' else 'failed' end
-- close the concat function and terminate the query
);
-- test result.
해당 쿼리를 실행하면 다음 결과가 생성됩니다. For every (year, month) there is one and only one (absolute_month): passed
month_value에 충분한 테스트 데이터가있는 한이 테스트가 작동합니다.
충분한 테스트 데이터에 대한 테스트도 추가 할 수 있습니다.
select concat( 'Sufficient and sufficiently varied month_value test data: ',
case when
( select count(distinct year, month) from month_value) > 10
and ( select count(distinct year) from month_value) > 3
and ... more tests
then 'passed' else 'failed' end );
이제 연속 테스트 해 봅시다.
select concat( '(absolute_month)s are consecutive: ',
case when ( select count(*) from cm_absolute_month a join cm_absolute_month b
on ( (a.month + 1 = b.month and a.year = b.year)
or (a.month = 12 and b.month = 1 and a.year + 1 = b.year) )
where a.absolute_month + 1 <> b.absolute_month ) = 0
then 'passed' else 'failed' end );
이제 쿼리에 불과한 테스트를 파일에 넣고 데이터베이스에 대해 해당 스크립트를 실행 해 보겠습니다. 실제로, 데이터베이스에 대해 실행할 스크립트 (또는 스크립트, 관련 뷰당 하나의 파일 권장)에 뷰 정의를 저장하면 동일한 스크립트 에 각 뷰에 대한 테스트를 추가 할 수 있습니다. -) 뷰를 생성하면 뷰의 테스트도 실행됩니다. 이렇게하면 뷰를 다시 만들 때 회귀 테스트를받을 수 있고 뷰 생성이 프로덕션에 대해 실행될 때 뷰도 프로덕션에서 테스트됩니다.