0307 TIL

looggi·2023년 3월 7일
1

TILs

목록 보기
28/114
post-thumbnail

데이터베이스

데이터베이스 트리거

  1. 데이터베이스 트리거에 대해 설명하고, 트리거를 쓰는 이유에 대해 말하세요.
    트리거는 특정 테이블에 대한 이벤트에 반응해 INSERT, DELETE, UPDATE 같은 DML 문이 수행되었을 때, 데이터베이스에서 자동으로 동작하도록 작성된 프로그램입니다.
    사용자가 직접 호출하는 것이 아닌, 데이터베이스에서 자동적으로 호출한다는 것이 가장 큰 특징입니다.

테이블에 대한 이벤트에 반응해 자동으로 실행되는 작업을 의미한다. 트리거는 데이터 조작 언어(DML)의 데이터 상태의 관리를 자동화하는 데 사용된다. 트리거를 사용하여 데이터 작업 제한, 작업 기록, 변경 작업 감사 등을 할 수 있다.
일반적으로 트리거는 다음의 3 가지 경우에 시작된다. 트리거는 SELECT 문에 의한 데이터 검색에 영향을 미칠 수 없다.

INSERT (새로운 행 삽입)
UPDATE (기존 행의 변경) / UPDATE OF (기존 행의 특정 열 변경)
DELETE (기존 행 삭제)

ex. 일매출 집계에서 추가삭제/업데이트되는 레코드 자동 계산
https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4_%ED%8A%B8%EB%A6%AC%EA%B1%B0

옵티마이저

  1. 옵티마이저(Optimizer)에 대해 아는대로 말해주세요.
    옵티마이저는 SQL을 가장 빠르고 효율적으로 수행할 최적의 처리 경로를 생성해주는 DBMS 내부의 핵심 엔진입니다.
    SQL을 작성하면 옵티마이저가 쿼리문에 대해 여러가지 실행 계획을 세우고, 최고의 효율을 갖는 실행계획을 판별한 후 그 실행계획에 따라 쿼리를 수행합니다.
    옵티마이저는 크게 규칙기반, 비용기반 옵티마이저로 구분되며 규칙기반 옵티마이저는 우선순위가 높은 규칙에 따라서 실행 계획을 생성하며, 비용기반 옵티마이저는 시스템 통계정보를 이용하여 처리비용이 적은 실행계획을 생성하고 실행합니다.

DB 튜닝

  1. DB 튜닝(Tuning)이 무엇인지 그리고 튜닝의 3단계에 대해 설명해주세요.
    DB 튜닝이란 DB의 구조나, DB 자체, 운영체제 등을 조정하여 DB 시스템의 전체적인 성능을 개선하는 작업을 말합니다.
    튜닝은 DB 설계 튜닝 → DBMS 튜닝 → SQL 튜닝의 3가지 단계로 나누어집니다.
    DB 설계 튜닝은 데이터 모델링, 정규화 등을 통해 할 수 있고, DBMS 튜닝은 메모리 관점의 튜닝으로 버퍼 풀 이나 커밋 주기 조절 등을 통해 할 수 있습니다. 마지막으로 SQL튜닝은 옵티마이저를 사용하거나 인덱스 활용여부 및 조인 순서 결정과 같은 SQL문 처리를 통해 하게 됩니다.

단계별 튜닝의 종류

가 더 맞는 것 같음

DB 설계 튜닝(분석/설계 단계) → DBMS 튜닝(개발/구현 단계) → SQL 튜닝(개발/구현 단계)

DB 설계 튜닝(모델링 관점)
효율성이 가장 크다

  • DB 설계 단계에서 성능을 고려하여 설계
  • 데이터 모델링, 인덱스 설계
  • 데이터파일, 테이블 스페이스 설계
  • 데이터베이스 용량 산정
  • 튜닝 사례 - 반정규화, 분산파일배치

DBMS 튜닝(환경 관점)

  • 성능을 고려하여 메모리나 블록 크기 지정
  • CPU, 메모리 I/O에 관한 관점
  • 튜닝 사례 - Buffer 크기, Cache 크기

SQL 튜닝(App 관점)

  • SQL 작성 시 성능 고려
  • Join, Indexing, SQL Execution Plan
  • 튜닝 사례 - Hash / Join
    -> 어떤 딕셔너리를 활용하는지, 메모리 영역을 어떻게 활용하는지, sql문의 호출빈도등을 고려하여 평균응답시간을 개선시킴

데이터베이스 튜닝의 3단계

데이터베이스 환경 분석 → 데이터베이스 성능개선 이행 → 데이터베이스 성능개선 평가

튜닝 실행 후

http://blog.skby.net/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%ED%8A%9C%EB%8B%9D-db-tuning/
https://travislife.tistory.com/25
https://dlevelb.tistory.com/745

프로그래머스 문제 풀기

➡️ 상위 n개 레코드

MySQL

SELECT NAME FROM ANIMAL_INS ORDER BY DATETIME LIMIT 1

https://m.blog.naver.com/jwlee0208/10096564579

➡️ 오픈채팅방

def solution(record):
    record=[re.split(' ') for re in record]
    id_nick={}
    answer=[]
    for re in reversed(record):
        if re[1] not in id_nick.keys() and re[0] !='Leave':
                id_nick[re[1]]=re[2]
    for re in record:
        if re[0]=='Enter':
            answer.append(id_nick[re[1]]+'님이 들어왔습니다.')
        elif re[0]=='Leave':
            answer.append(id_nick[re[1]]+'님이 나갔습니다.')
    return answer

레코드의 [명령어 아이디 닉네임]이 띄어쓰기로 구분되어 들어오기때문에 문자열을 split해서 하나의 리스트로 만들어주고 전체 레코드 리스트에 다시 넣어준다
id별 마지막 설정한 닉네임은 leave나 change 명령어로 시작하는 레코드에 저장되어있기때문에 레코드를 뒤집어서 뒤에서부터 leave 명령어가 아니고, 이미 저장되어있지 않은 레코드에 대해서만 딕셔너리로 {id:nickname} 저장한다
레코드에 대해서 완성된 화면을 출력한다

테스트 25 〉 통과 (123.43ms, 59.6MB)
테스트 26 〉 통과 (128.40ms, 61.9MB)
테스트 27 〉 통과 (139.65ms, 65.2MB)
테스트 28 〉 통과 (141.08ms, 65.9MB)
테스트 29 〉 통과 (133.99ms, 65.8MB)
테스트 30 〉 통과 (122.53ms, 61.2MB)
테스트 31 〉 통과 (122.02ms, 59.2MB)
테스트 32 〉 통과 (103.76ms, 53.7MB)

➡️ 단어 변환 (BFS) 남의 코드

변환 횟수가 최소가 되어야하므로 BFS를 써야한다

from collections import deque
def solution(begin, target, words):
    answer = 0
    q = deque([[begin, 0]]) # 큐 자료구조를 만들어주고 첫번째 노드를 만들어준다 q.append([begin,0])
    visited = [ 0 for _ in range(len(words))] # 노드 방문 여부 표시
    while q:
        word, cnt = q.popleft()
        if word == target:
            answer = cnt
            break        
        for i in range(len(words)):
            temp_cnt = 0
            if not visited[i]: # 방문한 적이 없는 노드
                for j in range(len(word)): 
                    if word[j] != words[i][j]:
                        temp_cnt += 1
                if temp_cnt == 1:
                    q.append([words[i], cnt+1])
                    visited[i] = 1
    return answer        

collections에서 deque를 임포트한다
deque 객체는 deque([ ]) 이렇게 생겨서 첫 줄처럼이 안에 첫번째 노드 값을 그냥 넣어줘도 되고 q.append([begin,0])이렇게 해도 된다
visited는 노드 방문 여부를 기록한다

큐에서 popleft로 왼쪽 노드 값을 꺼내서 word, cnt에 언패킹한다
만약 이 단어가 타겟 단어라면 cnt를 answer에 넣고 반복문을 벗어나서 answer를 리턴하게 된다
begin이 target과 다르다면 다음 for문을 진행한다.
전체 단어목록의 크기의 인덱스 i에 대해서 temp_cnt를 생성해준다.
방문한 적이 없는 노드에 대해서 단어(최초에는 begin)의 길이 인덱스 j를 이용해서 begin과 words의 i번째 단어의 각 자리 알파벳을 비교한다.
만약 다르다면 temp_cnt에 1을 넣어준다
temp_cnt==1일 때 한자리만 다르기 때문에 변환 가능한 단어가 되어서 큐에 넣어줄 수 있고 해당 순번 노드에 방문 표시를 한다

# begin="hit" ;	target="cog"
# words=["hot", "dot", "dog", "lot", "log", "cog"]
q: deque([['hot', 1]])
q: deque([['dot', 2], ['lot', 2]]) # begin과 한자리만 다른 단어들
q: deque([['lot', 2], ['dog', 3]]) # popleft로 왼쪽 값이 먼저 삭제됨
q: deque([['dog', 3], ['log', 3]]) # 그 다음 값은 자동으로 왼쪽으로 이동
q: deque([['log', 3], ['cog', 4]])
q: deque([['cog', 4]])
4 # return 값

통과를 못하긴 했지만 풀다보니 큐를 사용한 BFS 구현 코드랑 비슷하게 나왔던 게 진짜 신기했다 담엔 큐로 잘 풀 수 있으면 좋겠다

deque

from collections import deque
리스트랑 똑같이 생겼다고 생각하면 됨 트리아님
리스트의 extend() reverse() insert(위치, 값) remove(값) 사용 가능

  • 스택 구현: append() pop()
  • 큐 구현: appendleft() popleft() append() pop()

https://dongdongfather.tistory.com/72
https://hellominchan.tistory.com/156

언패킹

my_info = ['lee', '30', 'seoul', '010', 'xxxx', 'yyyy']
name, age, address, *unknowns = my_info

print(name)  # lee
print(age)  # 30
print(address)  # seoul
print(unknowns)  # ['010', 'xxxx', 'yyyy']

https://itholic.github.io/python-pack-unpack-1/

➡️ 뉴스 클러스터링

import collections

def solution(str1, str2):
    # 배열 만들기
    str1_list,str2_list=[],[]
    for i in range(len(str1)-1):
        if str1[i:i+2].isalpha():
            str1_list.append(str1[i:i+2].lower())
    for i in range(len(str2)-1):
        if str2[i:i+2].isalpha():
            str2_list.append(str2[i:i+2].lower())  
    # 모두 공집합일 경우 1 리턴
    if str1_list==[] and str2_list==[]:
        return 65536
    # 빈도 카운트 및 계산
    counter_1=collections.Counter(str1_list)
    counter_2=collections.Counter(str2_list)
    numerator,denominator=0,0
    for i in (set(str1_list)&set(str2_list)):
        numerator+=min(counter_1[i],counter_2[i])
    for i in (set(str1_list)&set(str2_list)):
        denominator+=max(counter_1[i],counter_2[i])
    for u in (set(str1_list)-(set(str2_list))):
        denominator+=counter_1[u]
    for u in (set(str2_list)-(set(str1_list))):
        denominator+=counter_2[u]                 
    return int((numerator/denominator)*65536) 

버림은 int로 구현할 수 있다

+배열 여러 개를 한번에 만드는 방법을 봤던 것 같은데 다시 찾아봐야지.. 이거 코드가 너무 창피하다 ㅠㅠ

✔️아래 3줄을 그냥 합집합으로 할 수 있다
나 첨에 합집합으로 했는데 왜 뭐 오류났겠지 또 .. 그래서 이것저것 수정하다가 이렇게 된듯.. 들고가기 전에 꼭 다시한번 고쳐봐야지 ㅠㅠ

for u in (set(str1_list)|(set(str2_list))):
        denominator+=max(counter_1[i],counter_2[i])

윗 부분도 리스트 축약식으로 바꾸면 더 간략하게 쓸 수 있다
축약식을 쓰면 먼저 빈 집합으로 선언하지 않아도돼서 더더 간략해진다
꼭 다시 해보고 가야지 흐

➡️ 최종 코드

import collections

def solution(str1, str2):
    
    str1_list=[str1[i:i+2].lower() for i in range(len(str1)-1) if str1[i:i+2].isalpha()]
    str2_list=[str2[i:i+2].lower() for i in range(len(str2)-1) if str2[i:i+2].isalpha()]
   
    if str1_list==[] and str2_list==[]:
        return 65536
    counter_1=(collections.Counter(str1_list))
    counter_2=(collections.Counter(str2_list))
	
    numerator,denominator=0,0
    for i in (set(str1_list)&set(str2_list)):
        numerator+=min(counter_1[i],counter_2[i])
    for u in (set(str1_list)|set(str2_list)):
        denominator+=max(counter_1[u],counter_2[u])
    return int((numerator/denominator)*65536)

아래도 그냥 축약식으로 바꾸자..

import collections

def solution(str1, str2):
    
    str1_list=[str1[i:i+2].lower() for i in range(len(str1)-1) if str1[i:i+2].isalpha()]
    str2_list=[str2[i:i+2].lower() for i in range(len(str2)-1) if str2[i:i+2].isalpha()]
   
    if str1_list==[] and str2_list==[]: #len(set1|set2) 해도 되네 진짜.. 
        return 65536
        
    counter_1=(collections.Counter(str1_list))
    counter_2=(collections.Counter(str2_list))
    
	numerator=sum([min(counter_1[i],counter_2[i]) for i in (set(str1_list)&set(str2_list))])
    denominator=sum([max(counter_1[u],counter_2[u])for u in (set(str1_list)|set(str2_list))])
    
    return int((numerator/denominator)*65536)

if str1_list==[] and str2_list==[]: 이 부분도 빈 배열이면 False니까 if not str1_list and not str2_list: 이렇게 해도 되고
len(set1|set2) 해도 된다 역시 리팩토링을 꼭 해야한다

profile
looooggi

0개의 댓글