//선언후, 초기화 방법
let dict1 = {}
dict1["apple"] = "사과";
dict1.orange = "오렌지";
console.log(dict1);
//변수 선언후, 변수명,값 으로 초기화 방법
let country = "한국";
let city = "서울";
let dict2 = {country, city};
console.log(dict2);
//생성 시 초기화 방법
let dict3 = {"apple":"사과", "orange":"오렌지"};
console.log(dict3);
결과물은 아래와 같음
키 사용
//딕셔너리 추가 및 데이터 활용
let dict = {"apple":"사과", "orange":"오렌지"};
dict.banana = "바나나"; //"banana" 추가
dict["melon"] = "메론"; //"melon" 추가
console.log(dict); //딕셔너리 전체 출력
console.log(dict.apple); //dict의 apple 참조
console.log(dict["melon"]); //dict의 melon 참조
console.log(Object.keys(dict)); // 키 값 전부 출력
console.log(Object.keys(dict)[2]); //키 값 배열 참조
결과물은 아래과 같이 해당 키의 값이 출력됨
키 분해하기 (변수에 저장)
기본 분해, 다른 이름의 변수에 분해
let dictionary = {name:"Tom", "age":28, "country":"Korea"} //키값은 ""으로 감싸지 않아도됨
// 기본적인 키 분해 (변수에 저장)
let {name, age} = dictionary; //변수 name, age 생성하며, dictionary의 name, age 값을 저장함
console.log(name); //"Tom" 출력, dictionary의 name값
console.log(age); //28 출력, dictionary의 age값
// 다른이름으로 키 분해 (다른이름의 변수에 저장)
let {country:nationality} = dictionary; //다른이름(nationality)으로 dictionary의 country값 저장
console.log(nationality); //"Korea 출력, dictionary의 country값
결과
기본값 지정 분해(없을경우 생성)
// 지정값 키 분해 (존재하지 않으면 지정값을 변수에 저장)
let dictionary = {name:"Tom", "age":28, "country":"Korea"} //키값은 ""으로 감싸지 않아도됨
let {name = "James", gender = "남성"} = dictionary; //변수 name, gender 생성하며, dictionary의 name, gender 값을 저장함, 단 없을경우 지정된 값으로 초기화
console.log(name); //"Tom" 출력, dictionary의 name값 (name 키값이 없는경우 James로 대체)
console.log(gender); //남성 출력, 지정된 초기값 "남성" 출력 (dictionary에 존재하지 않는 키, 지정값으로 초기화됨)
결과
나머지 분해(지정하지 않은 나머지도 생성)
// 나머지 키 분해 (나머지도 변수에 저장)
let dictionary = {name:"Tom", "age":28, "country":"Korea"} //키값은 ""으로 감싸지 않아도됨
let {name, ...others} = dictionary; //변수 name,others 생성하며, others에는 name을 제외한 dictionary가 저장됨
console.log(name); //"Tom" 출력, dictionary의 name값
console.log(others); //{"age":28, "country":"Korea"}출력, dictionary의 name을 제외한 나머지값 출력
결과
키 체크
let dict = {"apple":"사과", "orange":"오렌지"};
//키 체크 ("키값" in 사전변수)
console.log("tiger" in dict); // false 존재하지 않음
console.log("Apple" in dict); // false 대소문자 구분
console.log("apple" in dict); // True
Dictionary 길이 확인, length
// Object.keys(사전).length 형태로 사용하면 길이가 반환됨
// key 값이 같은경우
let data1 = {"Name" : "Jh", "Name":"TOM", "Name":"sue"}
console.log(Object.keys(data1).length); //길이 1 반환됨 (key값이 Name으로 동일하여 덮어씌워짐)
console.log(data1.Name); //console.log(data1["Name"]); //마지막에 입력된 "sue"가 출력됨
// 일반적인 사용
let data2 = {"Banana" : "바나나", "Tiger":"호랑이", "country":"국가"}
console.log(Object.keys(data2).length); //길이 3(키 3개)이 반환됨
// 딕셔너리 배열 사용할때
let data3 = [{"Name" : "TOM", "Age" : 24}, {"Name":"Jake", "Age":25}, {'Name':"John", "Age":23}, {'Name':"James", "Age":18}];
console.log(Object.keys(data3)); //['0', '1', '2', '3'] 배열 인덱스가 출력됨
console.log(Object.keys(data3[0])); //['Name', 'Age'] 0번 인덱스의 키가 반환됨
console.log(Object.keys(data3).length); //4 사전 배열의 길이가 반환됨
console.log(Object.keys(data3[0]).length); //2 0번 인덱스 사전의 키 길이가 반환됨
console.log(data3.length); //4 배열의 길이가 반환됨
--락 상태 확인
SELECT relation :: regclass, mode, granted, pid, * FROM pg_locks;
-- 실행중인 쿼리 확인
SELECT * FROM pg_stat_activity ORDER BY query_start ASC;
-- 활동중인 쿼리만 확인 ('1 sec'를 적어 1초가 지난 'active' 상태인 쿼리 확인)
SELECT current_timestamp - query_start AS runtime, datname, usename, pid, query
FROM pg_stat_activity
WHERE state = 'active' AND current_timestamp - query_start > '1 sec'
ORDER BY 1 DESC
granted가 True 면 락이 허가되어 실행중
락 걸린 쿼리 중지
-- 해당 쿼리만 중지 (PID를 매개변수로 적어주면됨)
SELECT pg_cancel_backend(3209);
-- 위의 명령으로 잠금이 풀리지 않을때, 상위 명령까지 전부 종료
SELECT pg_terminate_backend(3209) FROM pg_stat_activity;
락 종류
크게 Exclusive Lock 과 Shared Lock으로 나눌수 있음
Shared Lock은 읽기 잠금(read lock)이라고도 하며, 데이터를 동시에 읽을수 있게 허용하지만, 변경은 불가능한 상태 (Shared Lock이 한개라도 걸려있으면 Exclusive Lock을 걸수 없음)
Exclusive Lock은 쓰기 잠금(write Lock)이라고도 하며, 해당 락을 건 트랜잭션이 완료 될때까지 테이블, 혹은 레코드를 다른 트랜잭션에서 읽거나 쓰지 못함
------------------------------------------
ACCESS SHARE– SELECT 명령은 쿼리에서 참조된 테이블에서 이 잠금을 획득,일반적인 규칙은 테이블을 읽기만 하는 모든 쿼리가 이 잠금을 획득합니다.
ROW SHARE– SELECT FOR UPDATE 및 SELECT FOR SHARE 명령은 대상 테이블에서 이 잠금을 획득합니다(쿼리에서 참조된 모든 테이블에 대한 ACCESS SHARE 잠금).
ROW EXCLUSIVE– UPDATE, INSERT 및 DELETE 명령은 대상 테이블에 대한 이 잠금을 획득합니다(쿼리에서 참조된 모든 테이블에 대한 ACCESS SHARE 잠금).일반적인 규칙은 테이블을 수정하는 모든 쿼리가 이 잠금을 획득한다는 것입니다.
SHARE UPDATE EXCLUSIVE– VACUUM(FULL 제외), ANALYZE, CREATE INDEX CONCURRENTLY 및 일부 형태의 ALTER TABLE 명령은 이 잠금을 획득합니다.
SHARE– CREATE INDEX 명령은 쿼리에서 참조하는 테이블에 대한 잠금을 획득합니다.
SHARE ROW EXCLUSIVE– 어떤 명령으로도 암시적으로 획득되지 않습니다.
EXCLUSIVE– 이 잠금 모드에서는 이 잠금을 획득한 트랜잭션과 병렬로 읽기만 처리할 수 있습니다.명령에 의해 암시적으로 획득되지 않습니다.
ACCESS EXCLUSIVE– ALTER TABLE, DROP TABLE, TRUNCATE, REINDEX, CLUSTER 및 VACUUM FULL 명령은 쿼리에서 참조하는 테이블에 대한 잠금을 획득합니다.이 모드는 LOCK 명령의 기본 모드입니다.
최근 인덱스에 문제가 있어 Drop index 또는 Reindex index 를 통해 인덱스를 수정하려던 중 작동하지 않아 명령을 취소하였더니, 해당 테이블이 먹통이 돼버렸음 (원래 20ms 면 나오던 데이터가 10000ms를 넘겨서 나오는 현상이...)
해서 인덱스 상태를 확인한 결과 해당 테이블의 인덱스가 동작하지 않고있었음 (새로 추가되는 데이터만 인덱스 fetch되고 있었음)
-- Index 확인 쿼리
SELECT
schemaname AS schema_name,
relname AS table_name,
indexrelname AS index_name,
pg_size_pretty(pg_relation_size(indexrelid::regclass)) AS index_size,
idx_scan,
idx_tup_read,
idx_tup_fetch
FROM pg_stat_user_indexes
ORDER BY idx_scan ASC;
그래서 reindex 명령으로 인덱스를 살리려고 노력하는데 명령이 몇시간이 지나도 끝나지 않았음,
SELECT relation :: regclass, mode, granted, pid, * FROM pg_locks
확인해보니 granted가 막혀있었음, 다른 트랜잭션에서 이미 락을 걸고 사용중이었음, 사이트에 데이터가 너무 느리게 뜨자, 여기저기서 전화가;;;
급한대로 빨리 reindex를 해서 인덱스를 살려야 해서, 해당 relation과 관련된 락을 건 pid를 중지 시켰음
SELECT pg_cancel_backend(5957);
-- 위의 명령으로 중지해서는 먹히지 않아 아래껄로 중지함
SELECT pg_terminate_backend(5957) FROM pg_stat_activity;
첫번째 명령으로 처리가 안되어, 급한대로 아래의 pg_terminate_backend를 사용하여 상위 프로세스 까지 중지시켰음
SELECT * FROM pg_stat_activity ORDER BY query_start ASC;
동작 상태인 쿼리중 오래 걸리는 쿼리 확인
SELECT current_timestamp - query_start AS runtime, datname, usename, pid, query
FROM pg_stat_activity
WHERE state = 'active' AND current_timestamp - query_start > '1 sec'
ORDER BY 1 DESC
13분이나 처리를 못하고 말썽 피우는 쿼리
쿼리 중지시키기
--프로세스 ID값을 이용한 정지
SELECT pg_cancel_backend('PID');
--상위 프로세스 까지 정지
SELECT pg_terminate_backend('PID') FROM pg_stat_activity;
--저의 경우엔 PID가 23858
SELECT pg_cancel_backend(23858);
INSERT INTO 저장할테이블이름 (컬럼명1, 컬럼명2, 컬럼명3)
SELECT 컬럼명A, 컬럼명B, 컬럼명C FROM 불러올테이블이름
기본 INSERT 방법
-- 테이블에 존재하는 컬럼 갯수만큼 데이터를 지정해준경우
INSERT INTO 테이블명 VALUES(데이터A, 데이터B, 데이터C)
-- 일부 컬럼만 지정하여 값을 넣는 경우
INSERT INTO 테이블명 (컬럼명1, 컬럼명2,...) VALUES (데이터A, 데이터B,...)
-- 여러개의 튜플을 한번에 추가하는 경우
INSERT INTO 테이블명 (컬럼명1, 컬럼명2,...) VALUES
(데이터A, 데이터B, 데이터C,....),
(데이터K, 데이터L, 데이터M,....),
.
.
.
.
(데이터1, 데이터2, 데이터3,....);
-- SELECT를 통해 추가하는경우
INSERT INTO 테이블명A (컬럼명1, 컬럼명2, 컬럼명3, 컬럼명4,....)
SELECT *(또는 컬럼명시) FROM 테이블명B WHERE 조건