[An Introduction to SAP Sales and Distribution] Chapter 4 Customer Master]
What is business partner?
What is customer?
- 비즈니스에는 여러 타입의 비즈니스 파트너들이 있다. 조달 프로세스에서는 vendor(공급자) 혹은 vendor partner라고 불리고 영업 영역에서는 customer(고객)이라고 불린다. 예를 들어 customer는 Sold to party, Ship to party, Bill to party, Payer 등으로 나뉜다.
What is ship to party?
- 자재를 실제로 받게 되는 대상. 실제 고객과 다를 수 있다. 예를 들면 고객의 위탁판매를 하는 업체일 수 도 있다.
What is sold to party?
- 자재를 팔게 되는 대상자(주문 고객에 해당할 듯)
What is T-code for blocking a customer? How can we block a customer?
- T-CODE XD05, VD05에서 가능하다. VD05에서 block 할 경우 해당 고객에 대한 sales order가 막힌다. 마찬가지로 delivery와 billing도 막힌다.
- Delivery, Billing과 같이 각각의 영역을 막을 수도 있다.
What is account group for customer?
What is the importance of an account group?
How can we change a field from mandatory to optional?
- 계정그룹은다음과같은내역들을통제한다.
- number range :미리정의된번호범위가각각의계정그룹에따라할당되도록한다.
*번호 범위를 고객계정그룹에 지정 하는 것은 재무회계 IMG영역이다.
- internal or external number : 내부또는외부로번호를지정할지정할수있다. 위의이미지로판단한다면계정그룹이플랜트인경우와개인고객의경우에는사용자가직접해당번호범위내에의번호를입력하여고객을생성한다.
- 계정그룹에따라필수/선택필드를정할수있다.
*마찬가지로재무회계 IMG 세팅영역이다.
WhatisreconciliationG/Lcodeincustomermasterdata? Where and howthisG/Lisused?
- 조정계정(reconciliation GL) :고객과의거래가전기될때계상될계정지정(외상매출금, 대여금등고객의성격별로지정가능). 서비스와재화의인도가자금결제와동시에이루어지지않을때생기는채권성격의계정들이지정된다.(일반외상매출금, 관계회사외상매출금) 등
[An Introduction to SAP Sales and Distribution] Chapter 2 Organizational Structure, 3 Material Master]
What is the basic organizational structure in sales and distribution?
What are the organizational components in sales and distribution?
Organizational Structure란 SAP 시스템 관점을 통한 실제 회사의 구조적인 매핑(사상)이다. SAP이 가진 회사의 구조와 실제 회사의 구조를 서로 매핑 시키는 개념 혹은 기준정보라고 할 수 있다.
1. Client : SAP 시스템에서 유니크한 마스터 데이터나 특정한 configuration 세팅을 지닌 트랙잭션 데이터를 가지는 데이터베이스의 한 부분을 칭하는 조직 구조의 한 요소이다. 현실 세계의 회사 개념보다 위에 있는 개념이다. 현실과 매핑이 되지 않는 개념으로 시스템을 위한 분류이다.
2. Company Code : 한 클라이언트 하위에 독립적인 회계 단위를 가지는 조직 단위이다. 각 회사 코드는 재무제표(재무상태표, 손익계산서 등)를 각각 가진다.
3. Plant : 회사 코드 하위의 Operational Unit(운영 단위)로 보면 되는데 플랜트의 정의는 그 기능에 따라 달라질 수 있다. 생산이 일어나는 공장이나 사무실을 의미할 수도 있으며 단순히 재고의 입출고만 일어나는 물류센터를 의미할 수도 있다. Material의 평가는 플랜트 레벨에서 이루어진다(플랜트 마다 같은 자재여도 다른 평가값을 가질 수 있다는 의미).
4. Purchase Organization : 구매조직, 자재 확보에 대한 책임을 지니는 조직 단위
5. Purchasing Group : 구매 그룹, 하루 단위의 구매 행위가 구매 그룹에 의해 일어난다. 한 사람이 될 수도 있고 팀 등 그룹을 뜻할 수도 있다.
6. Storage Locations : 저장 위치, 재고가 물리적으로든 가상으로든 저장되는 장소이다. plant 혹은 plant area에 속한다. (plant area가 뭔지 모르겠음 현실의 개념을 말한 것 인가?)
7. Sales Organization : 영업 조직, 판매와 유통에 대해 책임과 통제를 맡는 조직 단위이다. SD모듈의 비즈니스 트랜잭션은 영업 조직에 의해 통제된다.
8. Sales Distribution Channel : 유통 채널, 어떤 자재와 상품이 고객이나 비즈니스 파트너에게 팔리거나 공급되는 매체를 의미한다. 예를 들면, 국내 유통, 수출, 소매, 도매 등의 분류를 의미한다. 이외에도 sales office나 sales group 조직 단위가 있다.
9. Sales Division : 제품군, 제품의 특정 군을 나타낸다. 2자리의 코드값으로 나타내며 material master 데이터에 할당되어 있다. sales order를 처리하는 과정에서 제품군은 가격과 다른 조건들을 결정하는 데 사용된다.
What is master data in SAP?
- 마스터 데이터란 주제(모듈이나 영역)에 관련된 기본적인 정보들을 기초로 생성된 데이터를 뜻한다.
자재 마스터, 고객 마스터, 조건 마스터, 총계정원장 등이 있다. 마스터 데이터라고 해서 반드시 "xxx 마스터" 라고 불리지는 않는다.
How many types of numbering are possible for material master?
What is internal material number assignment?
What is external material number assignment?
How internal and external material numbers can be assigned to material?
- 자재 마스터의 넘버링은 2가지 방식으로 이루어진다. 하나는 internal numbering, 다른 하나는 external 넘버링이다.
Internal Numbering은 시스템이 자동으로 사용가능한 다음 수를 가져와 자재 코드를 생성하는 방법이고 External Numbering은 사용자가 직접 자재를 생성하고 번호도 직접 입력하는 방식이다. 어느 방법을 사용하든 시스템은 허용된 넘버 레인지에서 자재 번호를 고르게 될 것이다. 넘버 레인지는 숫자나 알파벳만 가능하다.
What is industry sector?
- 산업 부문, 회사의 산업이 어떤 부문인지 고르는 것이다.
What are the basic views necessary in material master for sales processing?
- Basic Data 1, 2 뷰는 client-specific하다. 따라서 회사 코드와 플랜트에 관계 없이 같은 정보를 공유한다.
- base unit of measure : 재고가 관리되는 단위이다.
- material group : 자재나 서비스들을 각자의 특징으로 그룹화할 수 있다. 자재 그룹을 사용하면 분석의 범위를 정하는 데 사용할 수도 있고 search help를 통한 자재 마스터 검색에 도움을 줄 수 있다.
- division : 자재, 품목, 서비스 등을 묶는 방법 중 하나, 시스템은 division을 사용하여 자재에 대한 영업 영역이나 사업 영역등을 결정한다.
- cross-plant material status : 플랜트 간 자재 상태, 자재가 어떤 처리(processing)에 대해 보류(blocked) 상태인지 나타낸다. 자재가 보류되면 MM, PP, WM, PM 등의 모듈에서 보류될 것이다(사용 못함).
What is organization level only on request while creating a material master?
- 요청에 의한 조직레벨/프로파일 체크 시 시스템은 조직 레벨에 대한 상세 정보를 요구하지 않는다. 체크하고 자재를 생성하려고 하면 플랜트, 저장위치, 판매조직, 유통 경로에 대한 정보를 생성하지 않을 것이다.
- 조직 정보를 넣었을 때와 넣지 않았을 때의 영업 view 차이
What is cross-plant material status?
- 플랜트간 자재 상태 (플랜트 사이의 자재 상태가 아니라 cross-flatform이라는 용어처럼 모든 플랜트가 공유하는 자재의 상태를 뜻한다.)
- 자재를 특정 프로세스에 대해 보류(blocked) 상태로 만들 수 있다.
How, where and why account assignment group is used?
- 영업 view 2의 계정 지정 그룹은 Billing Document(대금청구문서)의 전기 시 미리 정의된 GL 계정으로 전기 되도록 유도하는 필드이다.
- 상품(Trading Goods), 제품(Finished Goods), Assets, Raw Material, 서비스 등으로 그룹을 지정할 수 있다.
What is NORM item category group?
- 판매 문서(Sales Order, Sales bill, Delivery document 등) 처리과정에서 시스템이 품목 범주를 결정하는데 도움을 준다.
시스템이 자동으로 설정된 품목 타입을 품목범주그룹에 따라 제시한다.
- HLevItCa는 Higher-Level Item Catogory인데 sub-item이 standard order의 품목에 할당되어 있는 경우 그 품목의 품목 범주가 HLevltCa가 된다. HLevltCa가 TAN인 경우 sub-item의 품목범주는 자동으로 TANN(무상품목)이 된다. 그렇게 되면 sub-item은 같은 오더에 포함되어 납품되지만 Billing이 생기지는 않게 할 수 있다. (BOM과 관련이 있기도 하니 나중에 찾아볼 것)
Determining the Item Category for Sub-Items
Services and free goods can be entered as separate items or can be allocated to other items. An item which is allocated to another one is called a sub-item. Determining the item category for sub-items depends on the higher-level item.
서비스와 무상품목은 개별 품목으로서 등록되거나 다른 품목에 할당될 수 있다. 어떤 아이템이 다른 아이템에 할당되는 경우 이것을 sub-item이라고 부른다. sub-item의 품목 카테고리 결정은 higer-level item에 의존한다.
If a free goods item is allocated to a standard item in a standard order (item category TAN), the item category TANN is used for the sub-item in the standard version of the SAP System, and the sub-item is processed as a free-of-charge item.
만약 무상품목이 표준 오더의 표준 품목(TAN)에 할당되면, SAP 스탠다드 프로세스 하에서는 하위 품목의 카테고리는 TANN이 된다. 그러면 하위 품목은 free-of-charge 품목으로 처리된다.
What is batch management?
- 배치 관리에 한 번 체크하면 다시 변경할 수 없다.
- 배치 관리를 하게 되면 재고 등록 시 시스템이 새로운 배치를 입력(배치번호입력)하라고 창을 띄운다. 재고 출고 시에는 재고가 속해있는 특정 배치 번호를 입력하게 된다.
SAP ERP 제품에 대해 전반적인 관리를 맡는 역할 : BC(Basic Component) 혹은 Basis라고 한다.
SAP BC의 역할
SAP 시스템 도입 시 하드웨어 ~ 시스템 구조 까지 전반적인 사항
ex) 설치, 사용자 관리, 라이선스 관리, 변경사항 적용(CTS), 패치, 모니터링, 튜닝 등
SAP 지식, 하드웨어, 네트워크, 운영체제, 데이터베이스 등에 대해 기본적인 소양이 있어야 함
SAP Netweaver란
WebServer나 WAS의 기능들을 제공하는 프로그램 , Apache나 Tomcat 생각하면 될 듯
Solman; Solution Manager
시스템 설치 시 Installation Key 발행
Support Package를 SAP Service Merket Place에서 내려받을 수 있도록 승인
이 외에도 다양한 기능들이 있음
SAProuter
Note를 자동으로 내려받아 적용할 수 있게 함
Basis와 여타 모듈에서 문제 발생 시 자체적으로 해결 불가능한 경우 SAP으로부터 직접 도움을 받을 수 있는데 이 때 SAProuter를 통해 SAP에서 직접적으로 도움을 받을 수 있다.
*Router :논리적, 또는 물리적으로 분리된 망 사이를 지나는 패킷의 위치에 따라 최적화된 경로(루트, route)를 지정하는 기능을 수행하는 장비
SAProuter도 마찬가지로 SAP 시스템과 다른 시스템들 간의 네트워크 연결에서 Proxy역할을 한다.
SAP Service Center와의 연결 등을 통제하는 기능이 있는 프로그램이라고 봐야할 듯
SAP 시스템의구성
NetWeaver란
SAP의 플랫폼, 이것 저것 다 이 기반 위에 올라가서 작동함
그냥 Web Server, WAS 등 미들웨어라고 생각하면 편할 듯 함
NetWeaver가 AS ABAP, AS Java를 포함하고 있고 2개의 서버 인스턴스가 NetWeaver에 들어있는게 dual-instance구조이다.
AS ABAP은 SAP GUI로 접근하는 요청을 처리하고
AS Java는 웹으로 접근하는 요청을 처리한다.
3 System Landscape
DEV(개발) -> QAS(품질) -> PRD(운영)
다른 웹 프로그래밍 구축 환경과 같이 3중 구조로 되어 있다.
Commit이라는 용어보다는 CTS(Change and Transport System)라는 용어를 사용한다.
SAP 시스템을 제외한 다른 기간계, 정보계 등 그룹웨어 시스템을 Legacy System라고 칭한다.
Client
클라이언트-웹서버-WAS-DB 등의 웹서비스 계층 구조를 말할 때의 Client가 아니라 SAP 시스템 안 에 속하는 고유 개념임 -> 그래서인지 SAP 문서 등을 살펴보면 혼동을 막기 위해 Web Client라는 용어를 사용하는 듯?
간단히 말해서 조직적/상업적/기술적으로 자신만의 데이터를 가지는 최소한의 관리 단위 정도로 보면 된다.
이에 대한 속성 변경은 SCC4에서 한다.
*DEV는 역할 별로 Client를 구분해 놓는 경우가 많아 Client가 많음(시스템 카피, IMG Master 등)
- 서버 내부 구조
CI(Central Instance)와 DI(Dialog Instance)
CI는 DB Instance와 Message Server, Enqueue Server 등 핵심 서비스를 포함한 시스템
DI(주로 AP1, AP2 등으로 표기)와 CI의 결정적인 차이점은 Message Server와 Enqueue Server가 없다는 것
Message Server로 유저가 접속하면 CI의 Message Server가 로드밸런싱을 통해 AP# 시스템으로 분산해주는 방식
Enqueue Server : The enqueue server receives a lock request and checks the lock table to determine whether the lock request collides with an existing lock. 데이터 lock 상태 관리 서비스인 듯. 데이터 처리 순서 통제하는 그런 건가 봄
SAP Work Process, SAP 시스템이 사용자 요청을 처리하는 방식
웹 브라우저를 통한 요청 -> ICM(Internet Communication Manager), 그 외 -> ABAP Dispatcher
Dispatcher는 자신의 queue에 요청을 넣고 FIFO방식으로 처리 -> 자신 아래에 있는 Work Process들에 일을 넘김(Spring Framework에서 Dispatcher Servlet과 Controller들의 관계인 듯)
유닉스 계열 서버에서 ps -df | grep sap으로 PPID(parent pid)가 같은 항목들이 있는데 그것들이 work precess들이고 그 PPID가 dispatcher의 pid임.
Work Process의 종류
D : dialog
V : update
E : Enqueue
B : Background
S : spool
G : gateway
M : message server
/usr/sap/<SID>/DVEBMGS00 -> 각 알파벳이 workprocess를 의미함 00은 인스턴스 번호(AP1은 01, AP2는 02로 되어 있을 거임)
포트번호
ABAP Dispatcher - 32##
ABAP Gateway - 33##
ABAP Message Server - 36##
ABAP ICM - 80## ( Web 요청을 받음 )
JAVA HTTP - 5##00
JAVA Message Server HTTP - 81##
JAVA P4 - 5##04 -> NetWeaver 7.1 부터 없어졌다함
JAVA Telnet - 5##08 ( AS JAVA를 관리하는 툴 )
SAPinst - 21212 ( SAP 설치 프로그램 )
SAP MC HTTP - 5##13 (SAP Management Control : SAP 종료/기동 등의 작업을 하는 툴 )
SAP 공식 사이트에 SAP 시스템의 각 서비스의 기본 포트번호와 범위를 알 수 있도록 게시해놓았음
sapstartsrv 라는 프로세스가 실행 중임 -> sapstartsrv는 SAP Start 프로그램으로 이 프로세스를 사용해 SAP을 구동시키고 종료함. (서비스명은 sapctrl)
5##13, 5##14 포트를 사용한다. ##은 인스턴스 번호
요청 처리과정
요청 in -> ABAP dispatcher가 받음 -> waiting 상태의 Work process에게 할당 -> Shared Memory영역에 있는 Roll Area의 User Context에서 사용자 권한 체크 -> 권한 있으면 처리(Screen Processer가 화면처리, ABAP Interpreter가 실제 ABAP 코드 처리)
보통 데이터베이스는 CI에 같이 설치되어 있어 DB접근 시 오라클의 SAP<SCHEMA-ID> (SAPSR3라는 사용자)로 접속
DI에서 DB 접근 시에는 먼저 OPS$.. 사용자로 운영체제 인증을 밭아 붙고 SAPUSER 테이블에서 비밀번호 가져와서 SAP<SCHEMA-ID>로 다시 붙음 -> remote_os_authent 값을 FALSE로 하면 DI가 정상적으로 작동하지 않을 것임!!
SAP 설치옵션 3가지
Central System : SAP 인스턴스와 데이터베이스가 하나의 장비에 모두 설치
Distributed System : DBI(데이터베이스 인스턴스)와 CI가 분리되는 형식
HA : Failover를 할 수 있는 형태로 설치
*1번 2번은 둘 중 하나 선택이지만 3은 1,2에 추가되는 옵션이라고 보면 될 듯
PAS는 CI의 새로운 명칭
ASCS는 두 가지 역할 : Message Server , Enqueue Server
ERS : HA(High Availability) 구성 시, Lock Table 정보를 노드 간에 동일하게 관리하기 위해 사용, Enqueue 서버가 하는 일을 백업하는 듯
HA 구성 : PAS-AAS를 제외하고 Cluster를 구성, ERS를 이용하여 데이터 lock 관리를 동기화하여 작업의 일관성을 유지한다. AAS는 HA 구성에서 Standby 서버
Disk 구성
SYS/global - Log File 있음
SYS/profile - SAP 시스템의 프로파일 위치함, 프로파일이란 파라미터들의 집합. SAP 시스템 시작 시 한 번 읽어들임. DEFAULT.PFL, Instance, Start 프로파일 (스프링에서 xml 설정 같은 건가 봄)
SYS/exe - SAP 시스템의 커널이 위치한 곳(The SAP kernel is the core component of any SAP system. It consists of the executable files that run on the server to handle connections to the system and execute the SAP programs.)
<INSTANCE>/work - Log 및 Trace파일 위치
<INSTANCE>/j2ee - AS JAVA 관련 파일 위치
<INSTNACE>/exe - 커널이 있는 곳, 시스템 시작 시 /SYS/exe 아래의 내용을 복사해 둔 곳.
SAP System의 기타 구성
NetWeaver 7.1부터는 듀얼 스택(AS ABAP과 AS JAVA가 같은 SID로 구성) 허용하지 않음 -> 2개 이상의 시스템이 하나의 데이터베이스를 공유하는 경우(MCOD : Multi Components in One Database)는 권장되지 않음.
SAP 시스템이 Oracle 데이터베이스로 설치될 떄 기본 스키마(소유자)는 AS ABAP은 SAPSR3, AS JAVA의 경우 SAPSR3DB이다. 이 떄 MCOD 형태로 설치되면 SAPSR3, 4 이렇게 되어야 한다. 그러나 설치 시 기존 시스템이 살아있지 않다면 SAPSR4가 아니라 SAPSR3로 만들어 기존 시스템을 다 날려버리게 됨.
듀얼 스택이라면 SM51에서 프로세스 확인하면 J2EE 프로세스가 보일 것임
다만 Solution Manager와 PI 제품은 듀얼 스택 허용(아예 이 형태로 설치됨)
*용어 : AS = Application Server, ECC = ERP Central Component, EhP = Enhancement Package
SAP ERP 6.06 = Enhancement Packege 6 for ERP 6.0 이라는 뜻, 제품군을 칭하는 용어가 막 다르니 그 때 그 때 찾아보면 될 듯
2022년도에 회계관리1급에 떨어지고 꽤 시간이 지나 다시 회계를 공부하여 지난 1월 말 재경관리사 시험에 합격했다.
지난 번 회계관리1급 시험은 회계사를 공부해봤다는 알량한 자신감을 가지고 공부를 안 했더니 떨어졌다.
그 후에는 그냥 저냥 안 좋은 기억으로 남겨뒀다가 최근에 SAP로 진로를 정하면서 회계 전반에 대해서 다시 공부해야겠다는 생각이 들어 기왕 공부하는 김에 자격증을 따자는 마음으로 재경관리사를 목표로 하게 되었다.
다른 자격증 공부와 달리 특별히 기억이 남아 이렇게 기록을 남긴다.
이번에 세법과목을 다시 공부하면서 내가 회계사 시험을 얼마나 대충 준비했는지 다시금 깨닫게 되었다. 100강이 넘는 세법 강의를 듣고도 법인세나 소득세의 계산구조, 영세율과 면세의 차이 같은 핵심 개념들도 이해하지 못하는 자신을 보면서 반성하게 되었다.
재경관리사가 엄청나게 어려운 시험은 아니다. ERP개발자, 금융권 개발자가 이 자격증을 가지고 있다고 해서 특별히 도움되는 것은 없을 수도 있다. 하지만 이번에 시험을 준비하며 느낀 건 제대로 "공부했다"와 "알고 있다"는 많이 다르다는 것을 다시금 깨달았다. 시험을 준비할 때는 문제를 풀 줄 알아야 공부를 제대로 한 것이다라는 단순한 사실을 다시 피부로 느꼈다.
재무회계와 원가관리회계를 수월하게 준비했기 때문에 오래 전 회계사 시험 공부의 효과가 전혀 없었던 것은 아니다. 특히 원가관리회계는 문제를 푸는 감각이 남아 있어 개념을 모르고도 계산 문제를 많이 맞췄다. 용어만 다르지 계산 방식은 거의 똑같기 때문이다. 그 감각이 남아있던 것이다. 재무회계도 마찬가지이다. 금융상품 회계는 문제풀이 연습도 거의 하지 않았지만 재경관리사의 문제들은 잘 풀 수 있었다.
문제는 세법이었다. 세법 개념강의를 다 들어갈 때 쯤 회계사 시험을 거의 포기했다. 이 많은 양을 1차 시험 전까지 복습할 자신도 없었기 때문에 틀려먹었다는 생각이 들어 속으로는 포기 상태였던 것이다. 재경관리사 세무회계 강의를 들으면서 문득 그 때 생각이 나 괴롭기도 했다. 스스로 한심하다는 생각도 들었다. 세무회계 강의를 다시 들으면서 공부에 대한 태도를 어떻게 가져야 할 지 배웠다.
세법을 들었으면 세법 문제를 풀 줄 알아야 하고, 영어를 공부했으면 읽고 쓰고 듣고 말할 줄 알아야 한다. 간단한 사실인데 제대로 하지 않았다는 것을 들킬까봐 항상 도망다녔다. 이제는 그러지 말고 스스로의 실력을 똑바로 인지해야 제대로 된 결실을 맺을 수 있다는 것을 배웠다.
앞으로 커리어 발전을 위해 다른 더 어려운 시험들을 준비하게 될 텐데 시험 전날 휴가를 써 밤새 공부했던 이번 시험 공부의 경험이 값지게 작용할 것 같은 예감이 든다.
→ SQL을 DBMS 내에서 프로시저로 만들어 낸다. 이 역할은 DBMS 내부 엔진인 SQL 옵티마이저가 담당한다.
즉, DBMS 내부에서 프로시저를 작성하고 컴파일하여 실행 가능한 상태로 만드는 전 과정을 ‘SQL 최적화’라고 부른다.
SQL 최적화 과정
SQL 파싱
파싱 트리 생성 : SQL문의 개별 요소를 분석하여 파싱 트리 생성
Syntax 체크 : 문법적 오류 점검
Semantic 체크 : 의미상 오류 점검(미존재 테이블 또는 컬럼의 사용, 오브젝트 권한 점검 등)
SQL 최적화
옵티마이저가 다양한 수집 정보를 이용하여 실행경로를 생성하여 비교 후 효율적인 하나를 선택 → 데이터베이스의 성능을 좌우하는 기능
옵티마이저가 사용 하는 정보
테이블, 컬럼, 인덱스 구조에 관한 정보
오브젝트 통계 : 테이블 통계, 인덱스 통계, 컬럼 통계 등
시스템 통계 : CPU 속도, Single Block I/O 속도, Multiblock I/O 속도 등
옵티마이저 관련 파라미터
최적화 과정 : 실행계획 찾기 → Data Dictionary에 수집된 정보, 시스템 통계 정보를 바탕으로 실행계획의 예상비용 산정 → 최저 비용 실행계획 선택
비용(cost)은 쿼리를 수행하는 동안 발생할 것으로 예상되는 I/O 횟수 또는 소요시간을 표현한 것 → 예상이므로 정확하지는 않을 수 있다.
로우 소스 생성
선택된 실행경로를 실제 실행 가능한 코드 또는 프로시저 형태로 Row-Source Generator이 포맷팅한다.
옵티마이저 힌트
힌트를 통해 데이터 엑세스 경로 조정
SELECT /*+ INDEX(A 고객_PK) */
고객명, 연락처, 주소, 가입일시
FROM 고객 A
WHERE 고객ID = '1000000123'
주석 기호에 +를 붙이면 된다.
주의사항
힌트 안에 인자 나열 시 힌트와 힌트 사이에 콤마 사용 x
테이블명 지정 시 스키마명 명시 x
FROM 절에 ALIAS 지정 시 힌트에도 반드시 ALIAS 사용
SELECT /*+ LEADING(A) USE_NL(B) INDEX(A (주문일자)) INDEX(B 고객_PK) */
A.주문번호, A.주문금액, B.고객명, B.연락처, B.주소
FROM 주문 A, 고객 B
WHERE A.주문일자 = #{ORD_DT}
AND A.고객ID = B.고객ID
/*
힌트 해설
LEADING(A): 가장 먼저 접근할 테이블나타냄
USE_NL(B): 고객(B)에 대해 Nested Loop Join을 사용하도록 힌트를 제공
INDEX(A (주문일자)): 주문(A)에서 주문일자 컬럼에 대해 인덱스를 사용하도록 힌트를 제공
INDEX(B 고객_PK): 고객(B)에서 고객의 PK에 대한 인덱스를 사용하도록 힌트를 제공
*/
위 처럼 힌트를 상세하게 쓰면 옵티마이저의 자유도를 제한할 수 있다.
자주 사용하는 힌트
최적화 목표
ALL_LOWS : 전체 처리속도 최적화
FIRST_ROWS(N) : 최초 N건 응답속도 최적화
2.액세스 방식
FULL : 테이블 풀스캔으로 접근 실행
INDEX : 인덱스 접근 실행
INDEX_DESC : 인덱스를 ORDER BY DESC 역순으로 실행
INDEX_FFS : INDEX FAST FULL SCAN
INDEX_SS : INDEX SKIP SCAN
조인순서
ORDERED : FROM절에 나열된 테이블 순서대로 조인
LEADING : 내가 힌트절에 열거한 테이블 순서대로 조인
SWAP_JOIN_INPUTS : 해시조인의 경우, BUILD INPUT를 명시적으로 선택
조인방식
USE_NL :NL(NESTED LOOP - 중첩루프) 방식 조인 유도
USE_MERGE : 소트머지 조인으로 유도
USE_HASH : 해시조인으로 유도
NL_SJ : NL SEMI조인으로 유도
MERGE_SJ : 소트머지 세미조인으로 유도
HASH_SJ : 해시 세미조인으로 유도
서브쿼리팩토링
MATERIALIZE : WITH문으로 정의한 집합을 물리적으로 생성하도록 유도
INLINE : WITH문으로 정의한 집합을 물리적으로 생성하지 않고 INLINE 처리하도록 유도
6.쿼리변환
MEERGE : 뷰 머징 유도
NO_MERGE : 뷰 머징 방지
UNNEST : 서브쿼리 UNNESTING 유도
NO_UNNEST : 서브쿼리 UNNESTING 방지
PUSH_PRED : 조인조건 PUSHDOWN 유도
NO_PUSH_PRED : 조인조건 PUSHDOWN 방지
USE_CONCAT : OR 또는 IN-LIST조건을 OR-EXPANSION으로 유도
NO_EXPAND : OR 또는 IN-LIST 조건에 대한 OR-EXPANSION방지
7.병렬처리
PARALLEL : 테이블 스캔, DML 병렬방식으로 처리하도록 할 때 사용
PARALLEL_INDEX : 인덱스 스캔을 병렬방식으로 처리하도록 유도
PQ_DISTRIBUTE : 병렬수행시 데이터 분배방식 결정
그외 기타
APPEND: DIRECT PATH INSERT유도
DRIVING_SITE : DB LINK REMOTE쿼리에 대한 최적화 및 실행 주체 지정 (LOCAL 또는 REMOTE)
PUSH_SUBQ : 서브쿼리를 가급적 빨리 필터링하도록 유도
NO_PUSH_SUBQ : 서브쿼리를 가급적 늦게 필터링 하도록 유도
SQL 공유 및 재사용
SQL 파싱 - 최적화 - 로우 소스 생성 과정을 거쳐 생성된 내부 프로시저를 반복 재사용할 수 있도록 캐싱해 두는 메모리 공간을 라이브러리 캐시(libarary cache)라고 한다. SGA(System Global Area)의 구성 요소이다
System Global Area (SGA) : 시스템 메모리(RAM)의 일부를 형성하고 하나의 오라클 데이터베이스 인스턴스에 속하는 프로세스들 모두에 의해 공유되는 시스템 메모리(RAM)의 일부 영역. 서버 프로세스와 백그라운드 프로세스가 공통으로 엑세스하는 데이터와 제어 구조를 캐싱하는 메모리 영역(서버 프로세스는 클라이언트의 요청 처리, 백그라운드 프로세스는 모니터링, 로깅 등의 보조 역할 프로세스)
소프트 파싱 vs 하드 파싱
소프트 파싱 : SQL을 라이브러리 캐시에서 찾아 곧바로 실행 단계로 넘어가는 것
하드 파싱 : SQL을 캐시에서 찾는 데 실패해 최적화 및 로우 소스 생성 단계 모두 거치는 것
SQL 재사용에 있어서 바인드 변수의 중요성
DBMS는 SQL을 일일히 저장하지 않는다 → 라이브러리 캐시에서 SQL을 찾기 위해 SQL문 그 자체를 찾는다.
SELECT * FROM CUSTOMER WHERE LOGIN_ID = 'ABC'
SELECT * FROM CUSTOMER WHERE LOGIN_ID = 'TOTO'
SELECT * FROM CUSTOMER WHERE LOGIN_ID = 'DADADA'
SELECT * FROM CUSTOMER WHERE LOGIN_ID = 'JAVAMAN'
위 SQL문은 DBMS가 실행할 때마다 내부 프로시저를 만들어 캐시에 적재하여 비효율이 발생한다.
이 때 파리미터 Driven 방식으로 SQL을 작성하는 방법을 사용하면 효율을 증대시킬 수 있다.
SELECT * FROM CUSTOMER WHERE LOGIN_ID = :1 -- <- 바인드 변수
위 SQL에 대한 하드 파싱은 한 번만 일어나고 캐싱된 SQL을 여러 사용자가 공유하여 사용할 수 있다.
이진 검색(binary search)은 요소가 오름차순 또순 내림차순으로 정렬된 배열에서 검색하는 알고리즘
중앙값을 가지고 비교 후 검색 범위를 반 씩 줄여나가는 방식이다. 그렇기에 배열이 정렬되어 있을 때 사용할 수 있음
검색에 필요한 비교 횟수의 평균값은 log n 이다.
public class Test1 {
public static void main(String[] args) {
int arr[] = {1,2,3,4,5,6,7,8,9,10,11,12};
int key = 1; // 찾을 값
int idx = BinarySearch.binSearch(arr, key);
System.out.println(arr[idx]);
}
}
class BinarySearch {
static int binSearch(int[] arr, int key) {
int n = arr.length;
int pl = 0; // 검색 범위 첫 인덱스
int pr = n -1; // 검색 범위 마지막 인덱스
int cnt = 0; // 검색 횟수
do {
cnt++;
int pc = (pl + pr) / 2; // 중앙값의 인덱스
if(arr[pc] == key) {
System.out.println("검색 횟수 : " + cnt);
return pc; // 찾으면 return
}
else if(arr[pc] < key)
pl = pc + 1; // 검색 범위 좁히기;
// key가 현재 선택한 값보다 크면 검색 범위 첫 인덱스를 선택한 수 바로 뒤로 옮긴다.
else
pr = pc - 1; // 검색 범위 좁히기
// key가 현재 선택한 값보다 작으면 검색 범위 마지막 인덱스를 선택한 수 바로 앞으로 옮긴다.
} while (pl <= pr); // 검색 범위 첫 인덱스가 마지막 인덱스보다는 같거나 작아야 함
System.out.println("검색 횟수 : " + cnt);
return -1;
}
// for문 이용
static int binSearchWithFor(int[] arr, int key) {
int n = arr.length;
int pl = 0; // 검색 범위 첫 인덱스
int pr = n - 1; // 검색 범위 마지막 인덱스
int cnt = 0; // 검색 횟수
for(pl = 0; pl <= pr; cnt++) {
//cnt++;
int pc = (pl + pr) / 2; // 중앙값의 인덱스
if(arr[pc] == key) {
System.out.println("검색 횟수 : " + cnt);
return pc; // 찾으면 return
}
else if(arr[pc] < key)
pl = pc + 1; // 검색 범위 좁히기;
// key가 현재 선택한 값보다 크면 검색 범위 첫 인덱스를 선택한 수 바로 뒤로 옮긴다.
else
pr = pc - 1; // 검색 범위 좁히기
// key가 현재 선택한 값보다 작으면 검색 범위 마지막 인덱스를 선택한 수 바로 앞으로 옮긴다.
}
System.out.println("검색 횟수 : " + cnt);
return -1;
}
}
복잡도
알고리즘의 성능을 평가하는 기준
시간 복잡도 : 실행에 필요한 시간 평가
공간 복잡도 : 메모리와 파일 용량이 얼마나 필요한가를 평가
연습문제
이진 검색 후에 찾은 값이 첫 번째로 등장하는 인덱스를 찾아서 반환
public class Test1 {
public static void main(String[] args) {
int arr[] = {1,2,3,4,5,6,7,11,11,11,11,23,45,67,123,124,125};
int key = 11;
int idx = findFirstKey(arr2, key2);
System.out.println(idx);
}
static int findFirstKey(int[] arr, int key) {
int n = arr.length;
int pl = 0; // 검색 범위 첫 인덱스
int pr = n - 1; // 검색 범위 마지막 인덱스
int pc = -1;
do {
pc = (pl + pr) / 2; // 중앙값의 인덱스
if(arr[pc] == key) {
// 첫번째로 나오는 key의 인덱스 찾기 => 찾은 인덱스의 왼쪽으로 가면서 같은 key인지 확인
for(int i = pc - 1; i >= 0;i--) {
if(arr[i] != key)
return i+1;
}
}
else if(arr[pc] < key)
pl = pc + 1; // 검색 범위 좁히기;
// key가 현재 선택한 값보다 크면 검색 범위 첫 인덱스를 선택한 수 바로 뒤로 옮긴다.
else
pr = pc - 1; // 검색 범위 좁히기
// key가 현재 선택한 값보다 작으면 검색 범위 마지막 인덱스를 선택한 수 바로 앞으로 옮긴다.
} while (pl <= pr); // 검색 범위 첫 인덱스가 마지막 인덱스보다는 같거나 작아야 함
return -1;
}
}
직선으로 늘어선 배열에서 원하는 키 값을 갖는 요소를 만날 때 까지 맨 앞부터 순서대로 요소 검색하는 방법, sequential search라고도 불린다.
조건
조건 1. 원하는 키 값을 만나 검색 중단
조건 2. 원하는 키 값을 만나지 못하고 전체 검색 후 종료
위 조건을 판단하는 횟수는 평균 n/2회
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
Scanner stdIn = new Scanner(System.in);
System.out.print("length : ");
int num = stdIn.nextInt();
int[] x = new int[num];
for(int i =0; i < num; i++) {
System.out.print("x[" + i + "] : ");
x[i] = stdIn.nextInt();
}
System.out.print("number to search : ");
int key = stdIn.nextInt();
int idx = SeqSearch.seqSearch(x, num, key);
System.out.println(idx);
}
}
class SeqSearch
{
static int seqSearch(int[] a, int n, int key)
{
int i = 0;
while(true) {
if(i == n) {
return -1; // 전체 검색하고 못 찾으면 -1 반환
}
if(a[i] == key) {
return i; // 찾으면 인덱스 반환
}
i++;
}
}
// for문으로 구현 시
static int seqSearchUsingFor(int[] a, int n, int key)
{
for(int i = 0; i < n;i++) {
if(a[i] == key) {
return i;
}
}
return -1;
}
}
보초법(sentinel method)
2개의 조건을 검사하는 비용을 50%으로 줄이는 방법
방법
대상이 될 배열보다 사이즈가 1개 더 큰 배열을 만들고 마지막에 찾을 값을 넣는다.
// int[] a는 검색하고자 하는 대상들이 들어있는 원래 배열보다 1큰 배열이어야 함
static int seqSearchWithSentinel(int[] a, int n, int key)
{
int i = 0;
a[n] = key; // 마지막에 더해진 공간에 보초값(key) 추가
while(true) {
if(a[i] == key) // 조건이 이전과 달리 1번만 들어감
break;
i++;
}
return i == n ? -1 : i; // 마지막까지 검색했으면 -1 리턴
}
Generics는 파라미터화된 타입을 의미한다. 즉, 메소드에 타입(Integer, String, 유저 정의 타입)을 파라미터로 하여 메서드, 클래스, 인터페이스에 전달할 수 있게 하는 기능이다. 이를 이용하여 다양한 데이터 타입을 가지고 동작하는 클래스를 만들 수 있다. 클래스, 인터페이스 또는 메서드와 같은 엔터티가 파라미터화된 타입에 기반에 수행된다면 이를 제네릭스 엔터티라고 한다.
왜 제네릭스를 쓰는가?
Object 클래스는 모든 다른 클래스들의 조상 클래스이다. Object 타입 참조 변수는 어떤 객체든 참조할 수 있다. 이런 특징은 타입 안정성을 해친다. 제네릭스를 사용하면 타입 안정성 효과가 있다.
JAVA의 Generics는 C++의 template과 비슷하다. HashSet,ArrayList, HashMap 등이 제네릭스를 잘 활용하고 있는 예이다. 제네릭 타입에 두 가지 접근법이 있는데 이 둘은 근본적으로 상당히 다른 점을 갖고 있다.
자바 제레릭스의 타입
Generic Method : 일반 메서드처럼 파라미터와 리턴값을 갖지만, actual type에 의해 인용되는 type parameter를 가지고 있다. 이는 제네릭 메서드가 더 범용적으로 사용되게 한다. 컴파일러는 타입 안정성을 고려하는데 이를 통해 프로그래머가 type casting 없이 쉽게 코드를 짤 수 있게 한다.
Generic Classes : 일반 클래스와의 차이점은 타입 파라미터 섹션을 가진다는 것 뿐이다. 하나 이상의 파라미터 타입이 있을 수 있다. 이런 클래스들을 parameterized classes 혹은 parameterized types라고 한다.
제네릭 클래스
public class Ex011 {
public static void main(String[] args) {
// Integer 타입 인스턴스
Test<Integer> iObj = new Test<Integer>(15);
System.out.println(iObj.getObject());
// String 타입 인스턴스
Test<String> sObj = new Test<String>("Str");
System.out.println(sObj.getObject());
}
}
class Test<T> {
// T 타입 오브젝트 선언
T obj;
// 생성자
Test(T obj) {
this.obj = obj;
}
public T getObject() {
return this.obj;
}
}
/*
15
Str
*/
여러 개의 타입 파라미터를 넣을 수도 있다
제네릭 메서드
public class Ex013 {
public static void main(String[] args)
{
genericDisplay(11);
genericDisplay("this is string");
genericDisplay(3.14);
}
static <T> void genericDisplay(T element)
{
System.out.println(element.getClass().getName() + " = " + element);
}
}
/*
java.lang.Integer = 11
java.lang.String = this is string
java.lang.Double = 3.14
*/
제네릭스는 기본형 타입과는 쓸 수 없고 참조형 타입하고만 어울릴 수 있다.
다만 기본형 타입 배열 같은 경우에는 괜찮다. 배열은 참조형이기 때문이다.
ArrayList<int[]> arr = new ArrayList<>(); // OK.
Test<int> obj = new Test<int>(20); // OK.
인자 타입이 다른 제네릭 타입을 쓰는 경우
package ch1;
public class Ex011 {
public static void main(String[] args) {
Test<Integer> iObj = new Test<Integer>(5);
System.out.println(iObj.getObject());
Test<String> sObj = new Test<String>("String is a string");
System.out.println(sObj.getObject());
iObj = sObj; // Type mismatch: cannot convert from Test<String>
}
}
class Test<T> {
// T 타입 오브젝트 선언
T obj;
// 생성자
Test(T obj) {
this.obj = obj;
}
public T getObject() {
return this.obj;
}
}
→ iObj, sObj 모두 Test 타입에 속하지만, 두 개는 각각 파라미터 타입이 다르기 때문에 다른 타입을 참조하고 있는 것이다. 제네릭스는 이런 타입 안정성 기능이 포함되어 있다.
네이밍 컨벤션
T - Type
E - Element
K - Key
N - Number
V - Value
제네릭스의 장점
코드 재사용
타입 안정성 : 컴파일러 단계에서 에러가 나 미리 알 수 있음
ArrayList al = new ArrayList(); // 타입 특정 X
al.add("Sachin");
al.add("Rahul");
al.add(10); // 컴파일러가 허용
String s1 = (String)al.get(0);
String s2 = (String)al.get(1);
String s3 = (String)al.get(2); // 런타임 에러 발생
/////////////////////////////////////////////////
ArrayList <String> al = new ArrayList<String> ();
al.add("Sachin");
al.add("Rahul");
al.add(10); // 컴파일 에러 발생하여 미리 방지 가능
String s1 = (String)al.get(0);
String s2 = (String)al.get(1);
String s3 = (String)al.get(2);
////////////////////////////////////////////////
ArrayList<String> al = new ArrayList<String>();
al.add("Sachin");
al.add("Rahul");
String s1 = al.get(0); // 굳이 타입 캐스팅 하지 않아도 됨
String s2 = al.get(1);
코드 재사용성
→ 비교 메서드의 재사용 예시
package ch1;
public class Ex015
{
public static void main(String[] args)
{
Integer[] a = { 100, 22, 58, 41, 6, 50 };
Character[] c = { 'v', 'g', 'a', 'c', 'x', 'd', 't' };
String[] s = { "Virat", "Rohit", "Abhinay", "Chandu","Sam", "Bharat", "Kalam" };
System.out.print("Sorted Integer array : ");
sort_generics(a);
System.out.print("Sorted Character array : ");
sort_generics(c);
System.out.print("Sorted String array : ");
sort_generics(s);
}
// T가 Comparable을 구현한 타입이어야 함
public static <T extends Comparable<T> > void sort_generics(T[] a)
{
for(int i = 0; i < a.length -1; i++)
{
for(int j = 0; j < a.length - i - 1; j++)
{
// Comparable 인터페이스는 compareTo 메서드를 가지고 있음
// <T extends Comparable<T> > 가 없다면 컴파일 에러 발생.
if(a[j].compareTo(a[j+1]) > 0)
{
swap(j, j+1, a);
}
}
}
for(T i : a)
{
System.out.print(i + ", ");
}
System.out.println();
}
public static <T> void swap(int i, int j, T[] a)
{
T t = a[i];
a[i] = a[j];
a[j] = t;
}
}