안녕하세요.

오늘은 데이터베이스 인덱스 개념에 대해 설명합니다.

인덱스란

인덱스(INDEX)DBMS의 검색 속도를 높이기 위한 기술 입니다.

DBMS는 데이터를 순차적으로 쌓으므로, 특정 데이터를 찾기 위해서는 데이터의 FULL-SCAN인 순차 탐색(O(N))이 필요합니다.

DBMS는 특정 데이터를 특별한 자료 구조로 쌓아 탐색 속도를 개선할 수 있는 기능을 제공합니다. 해당 기능을 인덱스라 부르고 쌓은 데이터들을 인덱스 테이블이라 부릅니다.

인덱스는 책의 목차와 비유할 수 있습니다. 우리가 책의 목차를 참고하여 필요한 내용으로 곧 바로 넘어가드시, DBMS인덱스 테이블에서 특정 인덱스를 찾아 필요한 행 데이터를 바로 가져옵니다.


인덱스 테이블

인덱스 테이블은 데이터를 조회할 때 사용되는 특정 컬럼의 데이터로 구성됩니다.

인덱스 테이블 에 포함된 데이터를 WHERE 문으로 조회를 하면 인덱스 테이블을 통해 ROW-ID를 빠르게 구한 뒤 단번에 행 데이터를 조회 할 수 있습니다.

인덱스 테이블 탐색

인덱스 테이블의 핵심은 빠른 조회 성능입니다. 이를 위해 인덱스 테이블은 탐색 트리 자료구조 중 하나인 B+트리 자료구조로 데이터를 저장합니다. 탐색 트리는 O(log2Nlog_2N) 성능의 빠른 조회를 할 수 있는 특징이 있습니다.

그렇기에, 데이터 FULL-SCAN[O(N)]성능에 비해, 압도적인 빠른 조회를 할 수 있는 장점 이 있습니다.

B+트리 포스팅을 참고해주세요.

인덱스 테이블 생성

TABLE을 생성 할 때, PRIMARY_KEY를 지정한 컬럼은 자동적으로 PRIMARY_KEY를 기준으로 인덱스 테이블이 생성됩니다.

만약 다른 컬럼을 인덱스 테이블을 생성하고 싶다면, 직접 생성해야 합니다.


인덱스 장점

인덱스의 장점은 곧 B+트리 자료구조의 장점과 일맥상통 합니다.

빠른 조회

인덱스 테이블은 메모리에 저장되어 있는 B+트리 자료구조 입니다.

메모리는 한정적인 자원이기 때문에 DBMS인덱스로 지정한 컬럼 데이터와 ROW-ID로 구성된 최소한의 노드로 B+트리를 구성합니다.

ROW-ID는 파일에 저장되어 있는 행 데이터를 가져올 수 있는 정보입니다.

여기에서 알 수 있는 재미있는 특징이 하나 있습니다. 데이터 FULL-SCAN이 느린이유는 순차탐색인 이유도 있지만, 빈번한 파일IO도 많은 영향을 미칩니다.

반면에 빠른 메모리 조회로 행 아이디를 찾는 인덱스 방식은 최소한의 파일IO를 사용합니다. 최소한의 파일IO는 더욱 빠른 탐색 속도를 가능하게 합니다.

데이터 정렬

만약 인덱스된 컬럼으로 정렬 명령을 내린다면 정렬 비용을 아낄 수 있습니다.

B+트리 구조상 조회된 데이터를 가져오기만 해도 정렬된 데이터를 획득할 수 있기 때문입니다.


인덱스 단점

지금까지의 설명만 보자면 인덱스 기능은 매우 훌륭한 기능 같습니다만, 그에 못지 않은 단점도 존재합니다. 대표적으로 아래와 같은 단점이 존재합니다.

  • 인덱스 테이블 유지 비용 (B+트리 유지비용)
  • 인덱스 테이블 추가 공간 비용

인덱스 테이블 유지 비용

B+트리의 중요한 특징 중 하나는 균형 이진 트리를 구성한다는 점 입니다. 노드의 삭제, 삽입시 트리 균형을 위해 트리 구조를 재구성 하는 비용이 발생합니다. 더군다나 탐색 이진 트리의 업데이트는 삭제 + 삽입 과정이 발생하므로 2배의 비용이 발생하게 됩니다.

위에서 살펴본 B+트리의 특징이 인덱스 테이블에도 똑같이 적용됩니다.

즉, O(log2Nlog_2N)으로 빠르게 조회가 가능하지만 삽입, 삭제, 업데이트 작업은 노드의 위치 탐색 비용 + 트리 재구성 비용 이 발생하게 됩니다.

DBMS는 트리 재구성 비용이라도 아끼기 위해 노드 삭제를 진행하지 않습니다. 대신 해당 노드에 사용하지 않는다는 마킹만 진행합니다. 그로인해 DBMS의 삭제, 업데이트 명령은 노드의 위치 탐색 비용만 발생하게 됩니다.

인덱스 테이블 추가 공간 비용

인덱스 테이블의 노드 삭제를 하지 않음으로써, 트리 재구성 비용을 아낀 전략은 유효해 보입니다. 하지만 이 역시도 다른 문제가 존재합니다.

그 문제는 바로, 인덱스 테이블이 거대해짐에 따라, 트리의 높이가 깊어지는 문제 입니다.

이는 테이블의 행 개수 보다 많은 개수의 저장공간을 필요로 합니다.

하지만 더욱 결정적인 문제는 트리 높이에 따른 성능으로 인해 인덱스 테이블 의 깊은 높이는 DBMS 성능을 점진적으로 내린다는 점 입니다.

결론적으로, 미 사용 노드를 트리에서 제거함으로써 높이 최적화가 필요함 을 알 수 있습니다. DBMS는 트리 높이 최적화를 수행하는 명령을 제공합니다. 해당 명령을 주기적으로 수행함으로써 전체적인 DBMS 성능을 높일 수 있습니다.


인덱스 생성 전략

위에서 살펴본 인덱스의 단점을 통해, 다음과 같은 결론을 도출 할 수 있습니다.

조회보다 삽입, 삭제, 업데이트가 더 많이 발생하는 테이블은 인덱스 기능이 오히려 단점이 될 수 있습니다.

또한 인덱스를 설정할 때는 유의할점이 몇개 존재합니다.

Cardinality 체크

인덱스를 구성할 땐, 컬럼의 Cardinality 를 고려하여 생성해야 합니다.

Cardinality 란 값의 분산도를 의미합니다. 다르게 표현하자면 값이 형태가 얼마나 다양하게 나올 수 있느냐의 척도입니다. 만약 (Y, N) 2가지 값으로만 구성된 컬럼을 인덱스로 설정하는 것은, 1700 페이지로 구성된 책에 목차가 2개만 존재하는것과 마찬가지 효과 입니다.

그렇기에 행 데이터가 최대한 많이 분류될 수 있는 컬럼으로 인덱스를 생성해야 효과적입니다.

조회 조건 빈번도 체크

당연한 얘기일 수 있겠지만, 조회 조건으로 자주 사용되는 컬럼일수록 인덱스 조건에 부합합니다.

아래의 항목은 간단한게 체크해볼 수 있는 리스트 입니다.

  • 조건절에 자주 등장하는 컬럼
  • LIKE 검색보다는 = 으로 검색하는 컬럼
  • ORDER BY 절에서 자주 사용되는 컬럼
  • JOIN으로 자주 사용되는 컬럼


지금까지 살펴본 내용을 요약하자면 다음과 같습니다.

  • 인덱스B+트리 구조를 통해 조회 성능을 올리는 기능입니다.
  • 데이터 FULL-SCAN은 빈번한 파일IO 작업을 통한 순차탐색으로 매우 느린 반면에 인덱스는 메모리에 저장된 트리 탐색을 통해 파일의 위치를 획득하여 파일IO 작업을 최소화 합니다.
  • 인덱스는 조회 성능을 높이고 삽입, 삭제, 업데이트 성능을 낮추는 트레이드 오프 기능 이므로 조회가 주된 목적인 테이블일 수록 유리합니다.
  • 인덱스는 조회가 주된 목적인 테이블일 수록 유리합니다.
  • 인덱스 테이블의 높이는 점점 깊어지므로, 주기적인 정리가 필요합니다.
  • 인덱스를 생성할 때는 Cardinality조회 조건 빈번도 체크가 필요합니다.

오늘 포스팅은 여기까지 입니다.

읽어주셔서 감사합니다.

'데이터베이스' 카테고리의 다른 글

[MySQL] 데이터베이스 원격 접속 명령어  (0) 2020.08.21
트랜잭션(Transaction)이란?  (26) 2017.02.27
Mysql 외부접근 설정하기.  (0) 2015.11.16

포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee

안녕하세요.

오늘은 B 트리 에 대해 포스팅 합니다.

B 트리이진 탐색 트리의 일종으로 탐색 성능을 높이기 위해 균형있게 높이를 유지하는 균형 트리 입니다.

균형 이진 탐색 트리는 대표적으로 RedBlackTree, AVL 트리 같은것이 있습니다. 두 트리가 독특한 규칙으로 높이를 유지 하는것처럼 B 트리도 자신만의 규칙이 존재합니다.

특이한점은, 이진 트리가 아니라는 점 입니다. 규칙에 따라 노드의 자식 노드 개수는 2개 이상이 될 수 도 있습니다.

B 트리 장점

B 트리의 장점은 크게 3가지가 존재합니다.

  • 균형 트리
  • 데이터 로드 효율성

균형 트리의 장점은 이진 탐색 트리 에서도 살펴봤다시피, 노드들이 한쪽으로 치우쳐 연결 리스트의 형태가 되는것을 방지하여 검색 효율을 높일 수 있다는 장점이 있습니다.

데이터 로드 효율성 측면은 대량의 데이터로 트리를 구성할 때, 진가를 발휘합니다.

데이터가 많은경우 메모리에 트리 구조를 유지하기 보다는 외부장치에 데이터를 저장해야 합니다. 각 노드의 값을 파일로 저장한 후, 파일 정보만 저장하고 있다면 메모리에서도 충분히 트리를 유지할 수 있게 됩니다.

외부장치에서 데이터를 읽어올때 데이터가 크던 작던 블럭 크기 만큼 읽어옵니다. 즉 노드의 데이터를 특정 블럭 크기 만큼 지정하여 저장 할 수 있다면 효율적으로 데이터를 읽어올 수 있다는 장점이 생깁니다.


B 트리 구성 방법

B 트리 만의 독특한 구성 규칙이 존재합니다. 이해를 위해서 모든 규칙은 맨 마지막에 정리하고, 중요한 조건순으로 차근차근 알아가봅시다.

N차 B 트리

B 트리를 구성할 때, 가장 중요한 조건은 노드가 최대 몇개의 데이터를 가질 수 있느냐 입니다.

만약 최대 3개의 자료를 가질 수 있다고 정의하면, 노드 자식 개수는 최대 4개를 가질 수 있습니다. 이때 최대 자식 개수를 사용하여 4차 B 트리 라고 표현 합니다.

즉 일반화 해본다면, 하나의 노드가 최대 M개의 자료를 가질 수 있다면 최대 자식 노드 개수는 M+1이 되므로 M+1차 B 트리 입니다.

왜 최대 자식 노드 개수가 M+1 이냐구요? 아래 B 트리 삽입 에서 살펴봅시다!

N차 B 트리는 노드의 최대 자료수는 N-1 이며, 최대 N개의 자식노드를 가질 수 있습니다.


B 트리 탐색

B 트리 탐색은 탐색 노드와 특징을 이용합니다.

특정 노드의 범위 위치를 찾은 후 아래의 자식 노드로 이동합니다.

아래의 과정은 0016 값을 찾는 과정입니다.

  • 루트 노드에서 0016 값의 범위 위치를 찾습니다. (0015 < 0016)
  • 다음 노드에 0016 값이 존재하는지 찾아봅니다. 존재하지 않으므로 0016 값의 범위 위치를 찾습니다. (0016 < 0017)
  • 다음 노드는 리프노드 이므로 해당 노드에 값이 존재하지 않는다면 트리에 값이 존재하지 않음을 알 수 있습니다. 0016 값이 있으므로 탐색을 종료합니다.


B 트리 삽입

B 트리의 차수를 정할 때 홀수냐 짝수냐에 따라 알고리즘이 조금 다릅니다. 홀수가 조금 더 계산하기 편하므로 홀수로 설명하겠습니다.

3차 B 트리 를 예시로 들어봅시다. (노드의 최대 자료 개수는 2개)

삽입의 핵심은 노드 분열 작업 입니다.

아래의 삽입 과정은 최초 노드 분열이 발생하는 과정입니다.

  • 01~02 번 삽입 과정은 루트 노드에 빈자리가 존재하여 자리를 찾아 삽입 합니다.
    • 데이터 저장 순서는 오름 차순으로 저장합니다.
  • 03번은 0011 을 루트 노드에 넣을 자리가 없는 경우 입니다.
    • 이때 B 트리 핵심 과정 중 하나인 노드 분열이 발생합니다.
    • 03-2. 루트 노드의 값들과 넣을 값을 포함하여 중간 값을 찾습니다. (홀수 차수를 고른것이 이때 편합니다.)
    • 03-3. 중간 값 0005 값을 부모 노드로 올리고, 왼쪽 값들과 오른쪽 값들을 자식 노드로 각각 구성하여 연결합니다.

아래의 과정에서 발생하는 노드 분열도 한번 살펴보시죠.

  • 04번 삽입은 탐색 노드 특징을 이용하여 리프노드 까지 도달합니다.
    • 리프노드에 자리가 비었으므로, 0017값이 그대로 저장됩니다.
  • 05-01. 0022 값의 자리를 탐색하여 리프 노드 까지 도달했습니다.
    • 05-01. 하지만, 리프 노드엔 자리가 없습니다. 노드 분열과 마찬 가지로 중간 값을 찾습니다.
    • 05-02. 중간 값을 부모 노드로 이동시킵니다. (노드 분열이 발생합니다.)
    • 05-02. 남은 값들은 각각 노드로 구성하여 중간 값 왼쪽, 오른쪽 자식노드로 연결합니다.

위 예시와 같이 리프노드에 공간이 부족할 때, 부모 노드로 중간 값을 옮기는 노드 분열를 수행하면 재밌는 특징이 생깁니다.

  • 규칙1. 노드의 자료가 최대 N개 라면, 해당 노드의 자식 노드 개수는 항상 N+1 입니다.
  • 규칙2. 모든 리프 노드들은 항상 같은 레벨에 위치하게 됩니다.
  • 규칙3. 노드의 자료가 최대 N개 라면, 리프 노드가 분열 할때 항상 중간 값으로 분열 하므로 노드의 자료 개수는 [N/2]~N개가 보장 됩니다.
    [3/2] ⇒ 2 (올림연산 입니다.)

마지막으로 아래의 노드 분열을 이해 하실 수 있다면, 트리 삽입 과정을 이해 하실 수 있습니다.


B 트리 삭제

B 트리의 삭제는 크게 두가지 케이스로 나누어 생각 해볼 수 있습니다.

  • 리프 노드에서 값 삭제.
  • 리프 노드가 아닌 중간 노드에서 값 삭제.

리프 노드에서 삭제

이 경우에도 크게 3가지 경우로 나뉩니다.

  • 리프 노드에서 값을 삭제 하더라도 최소 유지 개수 ([N/2]) 조건에 만족하는 경우.
  • 리프 노드에서 값을 삭제 할 때, 최소 유지 개수를 만족하지 못하지만 바로 옆 형제 노드들 중 최소 유지 개수 보다 많아 값을 빌려올 수 있는 경우.
  • 리프 노드에서 값을 삭제 할 때, 최소 유지 개수를 만족하지 못하고 옆 형제 노드들도 최소 유지 개수만 가지고 있어 값을 빌려올 수 없는 경우.

리프 노드에서 바로 삭제.

리프 노드가 최소 유지 개수를 만족하는 경우 바로 삭제가 가능합니다.

형제 노드에서 값을 빌려 오는 경우.

  1. 리프 노드형제 노드에서 빌려야 할 값을 찾습니다.
    • 오른쪽 형제 노드라면 형제 노드중 최대값.
    • 왼쪽 형제 노드라면 형제 노드중 최소 값.
  1. 리프 노드부모 노드에서 리프 노드형제 노드를 동시에 가리키고 있는 값을 찾습니다.
  1. 리프 노드에서 값을 삭제 후, 부모 노드에서 찾은 값을 리프노드로 내려주고 빌린 형제 노드 값을 부모 노드 찾은 값 자리에 넣습니다.

형제 노드에서도 값을 빌릴 수 없는 경우.

  1. 삭제할 리프 노드형제 노드를 병합 합니다. 병합 노드최소 개수 조건을 만족 시키기 위해 부모 노드에서 값 하나를 내려줍니다.
  1. 부모 노드도 최소 개수 조건을 만족하지 않는다면, 1번 과정을 리프 노드 대신 부모 노드로 치환하여 수행합니다.
  1. 만약 병합된 노드가 최대 개수를 넘는다면, 중간 값을 찾아 병합 노드의 부모 노드로 값을 넘겨줍니다.

중간 노드에서 삭제

해당 경우도 3가지로 나눌 수 있습니다.

  • 최소 개수 보다 많아 값을 빌려올 수 있는 자식 노드가 존재하는 경우.
  • 여유있는 자식 노드가 없지만, 부모 노드가 최소 개수보다 많은 경우.
  • 자식 노드도, 부모 노드도 여유가 없는 경우.

자식 노드에게 값을 빌려오는 경우.

  1. 값을 빌려올 자식 노드의 값을 찾습니다.
    • 왼쪽 자식 노드라면 최소 값을 찾습니다.
    • 오른쪽 자식 노드라면 최대 값을 찾습니다.
  1. 타겟 노드의 값을 지우고, 해당 자리를 찾은 자식 노드의 값으로 대체 합니다.

여유있는 자식 노드는 없지만, 부모 노드가 여유가 있는 경우.

  1. 노드의 삭제 값의 자식 노드들을 합병합니다.

자식노드, 부모노드 둘다 여유가 없는 경우.

  1. 노드의 삭제 값의 자식 노드들을 병합합니다.
  1. 노드의 형제 노드부모노드를 대상으로 병합을 진행합니다.
  1. 만약 병합 노드가 최대 개수를 초과 한다면 중간 값을 추출해 병합 노드부모노드로 이동시킵니다.


B+트리

B 트리의 단점은 순회?

Warning!! 주관적인 생각이 섞여 있습니다.

B 트리 는 자료 순회가 단점이라는 글이 많습니다. B 트리도 트리 구조이기 때문에 트리 순회와 똑같은 시간복잡도가 걸립니다. 그렇기에 단점이라 할 수는 없습니다.

많은 자료들이 단점이라 오해(?)하는 이유는 트리 순회를 개선한 B+트리의 존재 유무 때문이 아닐까 생각이 듭니다.

리프 노드들을 모든 노드의 값이 포함되도록 처리

B+ 트리의 순회 연산의 개선 포인트는 리프 노드들의 구조에 있습니다.

다음의 예시를 보면, 리프 노드들은 모든 값들을 포함하고 있고 연결리스트 형태를 구성하고 있습니다.

리프 노드의 위 노드들은 검색을 위해 유지하고 있는 모습입니다.

특정 범위를 순회하고 싶다면, 손쉽게 특정 리프 노드에서 차례대로 순회 할 수 있습니다.

빠른 검색-삽입-삭제 + 범위 검색 이 필요한 관계형 데이터베이스가 해당 자료구조를 사용하고 있습니다.


B 트리의 삽입, 삭제 과정을 단번에 이해하긴 어려운거 같습니다.

더군다나 트리의 특정 스냅샷 기준으로 설명했기 때문에 높이가 큰 트리인 경우에는 설명한 개념에 더해 재귀 개념 까지 합산하여 이해를 해야 하기 때문에 더 어려운거 같습니다.

B 트리 특징들을 살펴보면서 항상 만족했던 조건들을 다시 정리해보면 아래와 같습니다.

  • N차 B 트리는 노드의 최대 자료수는 N-1 이며, 자식노드는 최대 N개.
  • 노드의 자료가 최대 N개 라면, 해당 노드의 자식 노드 개수는 항상 N+1.
  • 노드의 자료가 최대 N개 라면, 노드의 자료 개수는 [N/2] ~ N개. (루트 노드 제외)
  • 모든 리프 노드들은 항상 같은 레벨에 위치한다.

오늘 준비한 포스팅은 여기까지 입니다.

읽어주셔서 감사합니다.

'자료구조' 카테고리의 다른 글

[자료구조] 이진탐색트리  (1) 2021.07.12
[자료구조] 트리(Tree)  (0) 2021.07.10

포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee




  안드로이드 UI의 상태나 가벼운 정보등은 SharedPreference(이하 S.P로 칭한다.)를 사용한다. 


db와 달리 번거롭지않고 사용하기 간편하기 때문이다. 


하지만 단점이 있다. xml형태로 저장하므로, 데이터 누적이 많아 지면 DB에 비해 성능이 떨어진다.


성능이 떨어지는 이유는 당연 인덱싱 문제가 아닐까 싶다. db같은 경우는 query로 손쉽게 원하는 데이터를 뽑아와


작업하지만, S.P 방식은 데이터 전부를 뽑아와 key값을 하나 하나 비교하기 떄문이라고 생각한다.


즉, 사용목적에 따라 두가지 기능(S.P , DB)을 적절히 사용 할 필요가 있겠다.


이번 포스팅은 db를 사용 할 것이다. 안드로이드는 SQLite이라는 내부 db를 제공해준다.


기본적인 셋팅은 아래와 같다.


public class MommooDB extends SQLiteOpenHelper {
public MommooDB(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {

}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
onCreate(db);
}

} 


SQLiteOpenHelper클래스를 상속받은 자신의 클래스를 만든다.


필수적으로 부모생성자와, onCreate, onUpgrade 이렇게 3가지를 적어줘야 한다.


필수 부모 생성자로 Context, 디비명, 커서, 버전을 아규먼트로 넘겨줘야한다.


여기서 Context는 안드로이드의 Context정보를 의마하고, 디비명은 자신의 데이터베이스 파일명을 의미한다.


커서는 db데이터를 다룰 때 쓰는데, 


자신의 만든 커스텀 커서가 있을경우 선언해주고 기본 커서를 사용할 경우는 null로 해준다.


마지막 매개변수는 버전이다. 같은 디비명이라도 버전이 틀리면 다른 디비로 간주 할 수 있다.


onCreate메서드는 혹, 자신이 호출하는 db명이 없는 경우 호출된다. 즉 새로운 디비를 만들때 


CREATE DB명 느낌보다는, db이름을  생성자에의 아규먼트로 넣어 실행했을 경우에


db명이 없을경우 onCreate메서드가 호출되고, db명이 있는경우는 호출하지 않는다.


따라서 db안의 table을 onCreate안에다가 관리하면 편하다.


onUpgrade메서드는 db명은 있지만 버전이 다른 경우에 호출돤다. 


즉 자신이 만든 db에 새로운 table을 추가한다거나


삭제같은 경우가 있을때, 자신의 디비의 버전을 올려주고 메서드 안에다가 새로운 작업을 하면 되겠다.


필자 같은 경우에 필요한 DB 정보는 id와 pass 데이터다. id와 pass 칼럼을 가지는 테이블을 작성해보겠다.


다음 포스팅때 마저 하겠다.




포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee




리눅스 서버를 구축한 후, Mysql 데이터베이스 환경을 만들었다.


Java로 서버연동을 해보려고 했지만, 잘 되지 않았다.


이유는 간단 했다. 데이터베이스를 초기에 만들때 접근 사용자 셋팅은 외부접근을 허용하지 않기 때문이다.


이유를 알았으니, 해결해보자.


GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';


위의 명령어를 실행 했을 경우, root 사용자는 모든호스트(%)에게 모든 권한을 허용하겠다는 의미이다.


조금더 응용해서 특정 IP 대역만을 허용하고 싶다 하면,


GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.%';


이런식으로 명령어를 써주면 되겠다. 192.168로 시작하는 IP대역의 외부접근을 허용하겠다는 의미이다.


권한설정후 Java로 연동해보니 잘 되었다.



포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee

+ Recent posts