개발자상식 <백엔드 개발자> (2)[책리뷰 & Book review]
본문 바로가기

컴퓨터공부/책리뷰 & book review

개발자상식 <백엔드 개발자> (2)[책리뷰 & Book review]

by Life & study 2024. 1. 13.
반응형

개발자상식 <백엔드 개발자> (2)

[책리뷰 & Book review]

 

 

 

데이터베이스 관리 능력
데이터베이스 설계 구조와 스키마 설계역할은 무엇인가?

 

데이터베이스 관리는 데이터의 저장, 검색, 수정, 삭제 등을 효율적으로 수행하기 위한 기술입니다. 

이를 위해 데이터베이스 관리 시스템(DBMS)이라는 소프트웨어를 사용합니다. 

DBMS는 관계형 데이터베이스(RDBMS)와 NoSQL 데이터베이스 등 다양한 종류가 있습니다.

데이터베이스 설계는 데이터베이스를 구축하기 전에 어떤 데이터를 어떻게 저장할 것인지 결정하는 과정입니다. 

이때, 데이터의 종류, 구조, 관계 등을 고려하여 효율적인 저장 방법을 찾아야 합니다. 

 

데이터베이스 설계는 주로 ER(Entity-Relationship) 모델을 사용하여 수행되며, 

이 결과를 데이터베이스 스키마로 변환하여 실제 데이터베이스에 적용합니다.

데이터베이스 스키마는 데이터베이스의 구조를 정의한 것입니다. 

이는 테이블, 필드, 데이터 타입, 관계 등 데이터베이스의 모든 부분을 포함합니다. 

스키마는 데이터베이스의 '틀'이라고 할 수 있으며, 이 안에 실제 데이터가 채워집니다.

아래는 MySQL을 사용하여 데이터베이스 스키마를 생성하는 간단한 예시입니다.

 

CREATE DATABASE mydb;  -- 데이터베이스 생성

USE mydb;  -- 데이터베이스 선택

-- 테이블 생성
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(50),
    password VARCHAR(50)
);

-- 다른 테이블 생성
CREATE TABLE posts (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT,
    title VARCHAR(100),
    content TEXT,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

 

이 예시에서는 users 테이블과 posts 테이블을 생성하고, 두 테이블 간의 관계를 정의하고 있습니다.

 users 테이블은 사용자의 정보를, posts 테이블은 게시글의 정보를 저장합니다.

 게시글은 어떤 사용자가 작성했는지 알 수 있도록 user_id 필드를 통해 users 테이블을 참조합니다.

이러한 데이터베이스 설계와 스키마 설계는 데이터의 일관성과 무결성을 유지하며,

 효율적인 데이터 처리를 가능하게 합니다. 

따라서, 데이터베이스를 다루는 능력은 데이터를 다루는 모든 분야에서 중요한 역량입니다.

 

한 줄 정리,

 

데이버베이스 스키마는 데이터베이스의 구조와 틀로써의 연결되는 부분을 말한다

 

데이터베이스 정규화란 무엇이냐?

 

데이터베이스 정규화는 데이터 중복을 최소화하고 데이터를 효율적으로 저장하기 위한 과정입니다. 

정규화는 주로 관계형 데이터베이스에서 사용되며, 여러 단계의 '정규 형태'를 거치게 됩니다. 

각 정규 형태는 데이터의 중복과 이상 현상(anomaly)을 줄이는 데 목표를 두고 있습니다.

 

데이터베이스 정규화는 데이터의 중복을 최소화하고 효율적으로 관리하기 위해 사용하는 기법입니다.

 이해를 돕기 위해 가상의 '도서 대출' 시스템을 예로 들어 설명해 보겠습니다.

첫 번째로, 제1 정규형(1NF)입니다.

이는 각 행이 유일한 키에 의해 식별되고, 각 열이 원자적 값만을 가지는 형태를 말합니다.

예를 들어, 도서 대출 시스템에서 '대출자' 테이블이 있을 수 있습니다.

sql
CREATE TABLE Borrowers (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    borrowed_books VARCHAR(255)
);


하지만 위의 테이블은 제1 정규형을 만족시키지 못합니다. 

왜냐하면 'borrowed_books' 열이 원자적이지 않고, 여러 권의 도서를 한 곳에 나열하고 있기 때문입니다. 

이를 해결하기 위해 각 도서를 별도의 행으로 분리해야 합니다.


두 번째로, 제2 정규형(2NF)입니다. 

이는 제1 정규형을 만족하면서, 부분 함수 종속성이 없는 형태를 말합니다. 예를 들어, 

'BorrowedBooks' 테이블에 'book_author' 열을 추가한다고 가정해 봅시다.

sql

CREATE TABLE BorrowedBooks (
    borrower_id INT,
    book_name VARCHAR(50),
    book_author VARCHAR(50),
    FOREIGN KEY (borrower_id) REFERENCES Borrowers(id)
);


하지만 위의 테이블은 제2 정규형을 만족시키지 못합니다. 

왜냐하면 'book_author' 열이 'book_name'에 부분적으로 종속되어 있기 때문입니다.

 이를 해결하기 위해 'Books' 테이블을 따로 만들어야 합니다.

 


 

마지막으로, 제3 정규형(3NF)입니다. 

이는 제2 정규형을 만족하면서, 이행적 함수 종속성이 없는 형태를 말합니다. 

예를 들어, 'Books' 테이블에 'publisher_name' 열을 추가한다고 가정해 봅시다.

sql

CREATE TABLE Books (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    author VARCHAR(50),
    publisher_name VARCHAR(50)
);


하지만 위의 테이블은 제3 정규형을 만족시키지 못합니다. 

왜냐하면 'publisher_name' 열이 'author'에 이행적으로 종속되어 있기 때문입니다. 

이를 해결하기 위해 'Publishers' 테이블을 따로 만들어야 합니다.

sql

CREATE TABLE Publishers (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);

CREATE TABLE Books (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    author VARCHAR(50),
    publisher_id INT,
    FOREIGN KEY (publisher_id) REFERENCES Publishers(id)
);


이처럼 정규화를 통해 데이터베이스의 구조를 개선하고, 중복을 최소화하며, 데이터의 무결성을 보장할 수 있습니다. 

하지만 모든 상황에서 정규화가 최선의 해결책은 아닙니다.

 때로는 성능 향상을 위해 일부 중복을 허용하는 비정규화도 필요할 수 있습니다. 

따라서, 데이터베이스 설계에 있어서는 상황에 따른 적절한 판단이 중요합니다.

 

 

 

 

 

 

데이터베이스 시스템 설치하고 설정하는 것

데이터베이스 연동에 API 나 ORM을 사용하여 데이터의
CRUD작업을 수행하는 것
<자바와 파이썬 편>

 

자바에서의 MySQL 연동

자바에서는 JDBC(Java Database Connectivity)라는 API를 통해 데이터베이스와 연동할 수 있습니다. 

먼저, MySQL Connector/J라는 JDBC 드라이버를 설치해야 합니다.

MySQL Connector/J 설치: 공식 홈페이지에서 다운로드 후, 압축을 해제하고 jar 파일을 프로젝트에 추가합니다.
데이터베이스 연결: JDBC를 통해 데이터베이스에 연결합니다.
java

import java.sql.*;

public class Main {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/database";
        String username = "username";
        String password = "password";

        try (Connection connection = DriverManager.getConnection(url, username, password)) {
            System.out.println("Database connected!");
        } catch (SQLException e) {
            throw new IllegalStateException("Cannot connect the database!", e);
        }
    }
}

 

 


CRUD 작업: PreparedStatement를 사용하여 SQL 쿼리를 실행합니다.

java

String sql = "INSERT INTO users (first_name, last_name) VALUES (?, ?)";

try (PreparedStatement statement = connection.prepareStatement(sql)) {
    statement.setString(1, "John");
    statement.setString(2, "Doe");

    int rows = statement.executeUpdate();

    if (rows > 0) {
        System.out.println("A new user has been inserted successfully!");
    }
} catch (SQLException e) {
    System.out.println(e.getMessage());
}

 


파이썬에서의 MySQL 연동

파이썬에서는 PyMySQL이라는 라이브러리를 통해 MySQL과 연동할 수 있습니다.

PyMySQL 설치: pip를 사용하여 PyMySQL을 설치합니다.
bash

pip install PyMySQL


데이터베이스 연결: PyMySQL을 통해 데이터베이스에 연결합니다.
python

import pymysql.cursors

connection = pymysql.connect(host='localhost',
                             user='username',
                             password='password',
                             database='database',
                             cursorclass=pymysql.cursors.DictCursor)

print("Database connected!")

 


CRUD 작업: cursor 객체를 사용하여 SQL 쿼리를 실행합니다.
python

with connection.cursor() as cursor:
    sql = "INSERT INTO users (first_name, last_name) VALUES (%s, %s)"
    cursor.execute(sql, ("John", "Doe"))

connection.commit()

print("A new user has been inserted successfully!")


이처럼 자바와 파이썬에서 각각 JDBC와 PyMySQL을 사용하여 MySQL과 연동하는 방법

 

 

 

 

 

데이터베이스와 통신을 위한 API나 ORM을 사용하여 

데이터 CRUD에 대한

자바와 파이썬 

 

자바와 파이썬에서 각각 JPA(Java Persistence API)와 SQLAlchemy라는 ORM(Object-Relational Mapping) 라이브러리를 사용해 CRUD 작업을 수행하는 방법을 알아보겠습니다.

1. 자바에서의 JPA 사용

JPA는 자바에서 제공하는 ORM 표준 스펙으로, 데이터베이스의 테이블을 자바 클래스로 매핑해 주는 역할을 합니다.

JPA를 사용하기 위해서는 먼저 JPA 구현체인 Hibernate 등을 프로젝트에 추가해야 합니다.

데이터베이스 연결 설정: persistence.xml 파일에 데이터베이스 연결 설정을 작성합니다.


xml

<persistence-unit name="myJPA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <properties>
        <property name="javax.persistence.jdbc.driver" value="cohttp://m.mysql.jdbc.Driver" />
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/database" />
        <property name="javax.persistence.jdbc.user" value="username" />
        <property name="javax.persistence.jdbc.password" value="password" />
    </properties>
</persistence-unit>

 


엔티티 클래스 생성: 데이터베이스 테이블을 대응하는 엔티티 클래스를 생성합니다.
java

import javax.persistence.*;

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    // getters and setters
}


CRUD 작업: EntityManager 객체를 통해 CRUD 작업을 수행합니다.
java

// Create
User user = new User();
user.setFirstName("John");
user.setLastName("Doe");
entityManager.persist(user);

// Read
User foundUser = entityManager.find(User.class, user.getId());

// Update
foundUser.setLastName("Smith");
entityManager.merge(foundUser);

// Delete
entityManager.remove(foundUser);

 


 

2. 파이썬에서의 SQLAlchemy 사용

SQLAlchemy는 파이썬에서 사용하는 ORM 라이브러리로, 데이터베이스의 테이블을 파이썬 클래스로 매핑합니다.
SQLAlchemy 설치: pip를 사용하여 설치합니다.
bash

pip install SQLAlchemy


데이터베이스 연결 설정: create_engine 함수를 사용하여 데이터베이스에 연결합니다.
python

from sqlalchemy import create_engine

engine = create_engine('mysql+pymysql://username:password@localhost:3306/database')


모델 클래스 생성: 데이터베이스 테이블을 대응하는 모델 클래스를 생성합니다.
python

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    first_name = Column(String)
    last_name = Column(String)

 

 

CRUD 작업: Session 객체를 통해 CRUD 작업을 수행합니다.
python

from sqlalchemy.orm import sessionmaker

Session = sessionmaker(bind=engine)
session = Session()

# Create
user = User(first_name="John", last_name="Doe")
session.add(user)
session.commit()

# Read
found_user = session.query(User).filter_by(first_name="John").first()

# Update
found_user.last_name = "Smith"
session.commit()

# Delete
session.delete(found_user)
session.commit()


이렇게 JPA와 SQLAlchemy를 통해 자바와 파이썬에서 각각 데이터베이스의 CRUD 작업을 수행하는 방법을 알아보았습니다. 각 라이브러리의 더 많은 기능과 상세한 사용법은 공식 문서를 참고하시기 바랍니다.

 

 

 

 

데이터베이스 성능 최적화: 백엔드 개발자는 데이터베이스의
성능을 최적화하는 역할을 수행한다
이는 쿼리를 실행 계획을 분석하고
인덱스를 적절하게 설정하여 데이터 검색과 조작 속도를
향상한다

 

데이터베이스의 성능 최적화는 매우 중요한 작업 중 하나입니다. 쿼리 실행 계획 분석 및 인덱스 설정을 통해 데이터 검색 및 조작 속도를 향상할 수 있습니다. 여기서는 MySQL을 예로 들어 설명하겠습니다.

쿼리 실행 계획 분석: MySQL에서는 EXPLAIN 명령어를 사용하여 쿼리의 실행 계획을 확인할 수 있습니다. 

EXPLAIN은 쿼리가 어떤 순서로 테이블을 스캔하는지, 어떤 인덱스를 사용하는지 등의 정보를 제공합니다.

 

EXPLAIN SELECT * FROM users WHERE first_name = 'John';
1 SIMPLE users const PRIMARY PRIMARY 4 const 1 Using where

 

 

 

이 결과를 분석하여 쿼리의 성능을 개선할 수 있습니다.

인덱스 설정: 인덱스는 데이터베이스에서 데이터를 빠르게 찾기 위한 자료구조입니다. 

적절한 인덱스 설정은 데이터 검색 속도를 크게 향상합니다. 

MySQL에서는 CREATE INDEX 명령어를 사용하여 인덱스를 생성할 수 있습니다.


sql

CREATE INDEX idx_first_name ON users (first_name);


이 명령은 users 테이블의 first_name 열에 인덱스를 생성합니다. 

이제 first_name 기반의 검색이 훨씬 빨라집니다.

하지만 인덱스는 공간을 차지하며, 데이터의 추가, 삭제, 수정 작업이 느려지게 하는 단점도 있습니다.

 따라서 꼭 필요한 곳에만 인덱스를 생성하는 것이 중요합니다.

이 외에도 정규화, 비정규화, 쿼리 최적화, 트랜잭션 관리 등 다양한 방법으로 데이터베이스 성능을 최적화할 수 있습니다. 이러한 작업은 시스템의 전반적인 성능을 크게 향상하므로, 백엔드 개발자로서 반드시 숙지해야 하는 기술 중 하나입니다.

 

 

 

 

 

 

 

'데이터베이스 쿼리의 성능을 개선하다'는 것은 무엇인가?

 

 

 

1 SIMPLE users const PRIMARY PRIMARY 4 const 1 Using where

각 칼럼의 의미는 다음과 같습니다.

 

 

id: 쿼리 내부의 순서를 나타냅니다.
select_type: 쿼리의 종류를 나타냅니다.
table: 접근하는 테이블을 나타냅니다.
type: 조인 혹은 테이블 스캔 유형을 나타냅니다.
possible_keys: 쿼리에서 사용 가능한 인덱스를 나타냅니다.
key: 실제로 쿼리에서 사용하고 있는 인덱스를 나타냅니다.
key_len: 사용하고 있는 인덱스의 길이를 나타냅니다.
ref: 인덱스를 참조하는 칼럼을 나타냅니다.
rows: 쿼리 실행을 위해 읽어야 하는 행의 수를 추정한 값을 나타냅니다.
Extra: 쿼리 실행에 대한 추가 정보를 제공합니다.
이를 통해 어떻게 성능을 개선할 수 있을지 생각해 봅시다.

인덱스 최적화: possible_keys와 key를 확인하여 쿼리에 사용된 인덱스를 확인합니다. 

이 인덱스가 쿼리 성능에 최적화되어 있는지 확인하고, 필요하다면 인덱스를 추가하거나 수정합니다.

 

기존 sql

EXPLAIN SELECT * FROM users WHERE first_name = 'John';

 

sql
-- 인덱스 추가

CREATE INDEX idx_first_name ON users (first_name);


조인 최적화: type를 확인하여 테이블 스캔 유형을 확인합니다.

 ALL 혹은 index 등 비효율적인 스캔 타입을 사용하는 경우, 쿼리를 수정하거나 인덱스를 추가/수정하여 조인 유형을 최적화합니다.


쿼리 수정: rows를 확인하여 쿼리 실행에 필요한 행의 수를 확인합니다. 이 값이 큰 경우, WHERE 절을 수정하거나 필요한 경우 쿼리 자체를 수정하여 읽어야 하는 행의 수를 줄입니다.


이렇게 EXPLAIN 명령어의 결과를 분석하여 쿼리 성능을 개선하는 방법을 알아보았습니다. 성능 최적화는 많은 경험과 지식이 필요한 작업이므로, 이 외에도 다양한 방법을 찾아보고 적용해 보시기 바랍니다.

 


 

1. 인덱스 추가 후의 변화

먼저, first_name에 대한 인덱스를 추가하면, first_name을 기준으로 데이터를 찾는 쿼리의 성능이 향상됩니다.

sql

CREATE INDEX idx_first_name ON users (first_name);


이제 EXPLAIN 명령어를 다시 실행해 봅시다.

sql

EXPLAIN SELECT * FROM users WHERE first_name = 'John';


아마 결과는 다음과 같을 것입니다.



id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE users const idx_first_name idx_first_name 4 const 1 Using where


이제 possible_keys와 key에 idx_first_name이 등장하였습니다. 

이는 쿼리가 first_name에 대한 인덱스를 사용함을 의미하며, 이로 인해 쿼리 성능이 향상되었을 것입니다.

 



2. 조인 최적화

조인 최적화를 위해서는 먼저 조인을 수행하는 두 테이블의 관계를 이해해야 합니다. 

예를 들어, users 테이블과 orders 테이블이 있다고 가정해 봅시다.

sql

EXPLAIN SELECT * FROM users INNER JOIN orders ON users.id = orders.user_id;


EXPLAIN의 결과를 통해 어떤 인덱스가 사용되었는지, 어떤 유형의 조인이 이루어졌는지 등을 확인할 수 있습니다. 

만약 ALL 혹은 index 등의 비효율적인 접근 방식이 발견된다면, 

해당 칼럼에 인덱스를 추가하여 성능을 향상할 수 있습니다.

sql

CREATE INDEX idx_user_id ON orders (user_id);


이렇게 인덱스를 추가하면, 조인 쿼리의 성능이 향상될 것입니다. 

이 외에도 쿼리의 작성 방식, 데이터의 분포, 

테이블의 크기 등 다양한 요소를 고려하여 조인을 최적화해야 합니다.

이렇게 인덱스 추가와 조인 최적화를 통해 쿼리 성능을 향상할 수 있습니다. 

하지만 항상 필요한 경우에만 인덱스를 추가하고, 

쿼리의 성능을 정기적으로 모니터링하며 최적화를 수행하는 것이 중요합니다.

 

 

반응형

댓글