SQL, ์ด๋ณด๋ค ๋ ๊ฐ๋จํ ๊ฒ์ ๋ฌด์์ผ๊น์? ์ฐ๋ฆฌ ๊ฐ์๋ ๊ฐ๋จํ ์์ฒญ์ ์์ฑํ ์ ์์ต๋๋ค. ๊ณ ๋ฅด๋ค, ํ์ ์ด์ ๋์ดํ ๋ค์ ์, ํ
์ด๋ธ ์ด๋ฆ, ์ผ๋ถ ์กฐ๊ฑด ์ด๋์ ๊ทธ๊ฒ ์ ๋ถ์
๋๋ค. ์ ์ฉํ ๋ฐ์ดํฐ๋ ์ฐ๋ฆฌ ์ฃผ๋จธ๋์ ์์ผ๋ฉฐ (๊ฑฐ์) ๊ทธ ๋น์ ์ด๋ค DBMS๊ฐ ๋ด๋ถ์ ์๋์ง์ ๊ด๊ณ์์ด(๋๋ ์๋ง๋)
๊ทธ๋ฆฌ๊ณ ๋ฐ๋ก ์์ํด๋ณด์
๊ฐ์ฒด ๊ด๊ณํ ๋งคํ
ORM ์ง์ง์๋ค์ ์ ํต์ ์ผ๋ก ์๋์ ๊ฐ๋ฐ ์ฉ์ด์ฑ, DBMS๋ก๋ถํฐ์ ๋ ๋ฆฝ์ฑ ๋ฐ ๊น๋ํ ์ฝ๋๋ฅผ ์ค์ํ๊ฒ ์๊ฐํฉ๋๋ค. ์ฐ๋ฆฌ ์ค ๋๋ถ๋ถ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค(๊ทธ๋ฆฌ๊ณ ์ข ์ข ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์ฒด) ์์ ์ ์ํ ์ฝ๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
๋ณดํต ์ด๋ฐ ๋ชจ์ต์ธ๋ฐ..
@Entity
@Table(name = "stock", catalog = "maindb", uniqueConstraints = {
@UniqueConstraint(columnNames = "STOCK_NAME"),
@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "STOCK_ID", unique = true, nullable = false)
public Integer getStockId() {
return this.stockId;
}
...
๋ชจ๋ธ์๋ ๊ธฐ๋ฐํ ์ฃผ์์ด ๋ฌ๋ ค ์๊ณ , ๊ทธ ์ด๋ฉด ์ด๋๊ฐ์์ ์ฉ๊ฐํ ORM์ด ์๋ง์ SQL ์ฝ๋๋ฅผ ์์ฑํ๊ณ ์คํํฉ๋๋ค. ๊ทธ๊ฑด ๊ทธ๋ ๊ณ , ๊ฐ๋ฐ์๋ ์ ํฌ๋ก๋ฏธํฐ์ ์ถ์ํ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์์ ์ ๊ฒฉ๋ฆฌํ๊ธฐ ์ํด ์ต์ ์ ๋คํ๊ณ ์์ต๋๋ค.
๋ฐ๋ฆฌ์ผ์ด๋์ ๋ฐ๋ํธ์๋ ์์ํ "์์ " SQL ์ง์ง์๋ค์ด ์ถ๊ฐ ๊ณ์ธต์ด๋ ์ถ์ํ ์์ด DBMS์์ ๋ชจ๋ ๊ธฐ๋ฅ์ ์ง๋ผ ์ ์๋ ๋ฅ๋ ฅ์ด ์๋ค๋ ์ ์ ์ฃผ๋ชฉํฉ๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ํน๋ณํ ๊ต์ก์ ๋ฐ์ ์ฌ๋๋ค์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฐธ์ฌํ๋ "๋ฐ์ดํฐ ์ค์ฌ" ํ๋ก์ ํธ๊ฐ ๋ํ๋๊ณ (๊ทธ๋ค์ "๊ธฐ๋ณธ์ฃผ์์"์ด๊ธฐ๋ ํ๊ณ "๊ธฐ๋ณธ์ฃผ์์"์ด๊ธฐ๋ ํ๋ฉฐ "๊ธฐ๋ณธ์ฃผ์์"์ด๊ธฐ๋ ํจ) ๊ฐ๋ฐ์๋ ๋ง์ฐฌ๊ฐ์ง์ ๋๋ค. ์ธ๋ถ ์ฌํญ์ ๋ค๋ฃจ์ง ์๊ณ ๋ฏธ๋ฆฌ ๋ง๋ค์ด์ง ๋ทฐ์ ์ ์ฅ ํ๋ก์์ ๋ง "ํ"ํ๋ฉด ๋ฉ๋๋ค.
์ฐ๋ฆฌ๊ฐ ๋ ์ธ๊ณ์ ์ฅ์ ์ ๋ชจ๋ ๊ฐ๊ณ ์๋ค๋ฉด ์ด๋จ๊น์? ์๋ช
์ ํ์ธํ๋ ์ด๋ฆ์ ๊ฐ์ง ํ๋ฅญํ ๋๊ตฌ์์ ์ด๊ฒ์ด ์ํ๋๋ ๋ฐฉ๋ฒ
Clojure๋ DSL์ ์์ฑํ๊ธฐ ์ํ ๋ฉ์ง ์ธ์ด์ด์ง๋ง SQL ์์ฒด๋ ๋ฉ์ง DSL์ด๋ฏ๋ก ๋ค๋ฅธ ์ธ์ด๊ฐ ํ์ํ์ง ์์ต๋๋ค. S-ํํ์ ํ๋ฅญํ์ง๋ง ์ฌ๊ธฐ์ ์๋ก์ด ๊ฒ์ ์ถ๊ฐํ์ง๋ ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ์ฐ๋ฆฌ๋ ๋๊ดํธ๋ฅผ ์ํด ๋๊ดํธ๋ฅผ ์ป์ต๋๋ค. ๋์ํ์ง ์์ต๋๊น? ๊ทธ๋ฐ ๋ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ ์ถ์ํ๊ฐ ๋์ถ๋๊ธฐ ์์ํ๊ณ ํจ์์์ ์ธ์์ด ์์๋๋ ์๊ฐ์ ๊ธฐ๋ค๋ฆฌ์ญ์์ค. (์์ SQL)
๊ทธ๋์ ๋ด๊ฐ ๋ฌด์์ํด์ผํ๋? SQL์ ์ผ๋ฐ SQL(์์ฒญ๋น ํ๋์ ํ์ผ)๋ก ๋จ๊ฒจ๋ก๋๋ค.
-- name: users-by-country
select *
from users
where country_code = :country_code
... ๊ทธ๋ฐ ๋ค์ ์ด ํ์ผ์ ์ฝ๊ณ ์ด๋ฅผ ์ผ๋ฐ Clojure ํจ์๋ก ๋ณํํฉ๋๋ค.
(defqueries "some/where/users_by_country.sql"
{:connection db-spec})
;;; A function with the name `users-by-country` has been created.
;;; Let's use it:
(users-by-country {:country_code "GB"})
;=> ({:name "Kris" :country_code "GB" ...} ...)
"SQL ์์ฒด, Clojure ์์ฒด" ์์น์ ์ค์ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ด์ ์ ์ป์ ์ ์์ต๋๋ค.
- ๊ตฌ๋ฌธ๋ก ์ ๋๋ผ์์ ์์ต๋๋ค. ๊ทํ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ (๋ค๋ฅธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ง์ฐฌ๊ฐ์ง๋ก) SQL ํ์ค์ 100% ์ค์ํ์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ Yesql์์๋ ์ค์ํ์ง ์์ต๋๋ค. SQL๊ณผ ๋๋ฑํ ๊ตฌ๋ฌธ์ ์ฌ์ฉํ๋ ํจ์๋ฅผ ์ฐพ๋ ๋ฐ ์๊ฐ์ ๋ญ๋นํ์ง ์์ ๊ฒ์ ๋๋ค. ํจ์๋ก ๋์๊ฐ ํ์๊ฐ ์์ต๋๋ค. (์์ SQL "some('funky'::SYNTAX)")).
- ์ต๊ณ ์ ํธ์ง์ ์ง์. ๊ทํ์ ํธ์ง์๋ ์ด๋ฏธ ๋ฐ์ด๋ SQL ์ง์ ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์์ต๋๋ค. SQL์ SQL๋ก ์ ์ฅํ๋ฉด ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ํ ํธํ์ฑ. DBA๋ Clojure ํ๋ก์ ํธ์์ ์ฌ์ฉํ๋ SQL์ ์ฝ๊ณ ์ธ ์ ์์ต๋๋ค.
- ์ฑ๋ฅ ํ๋์ด ๋ ์ฌ์์ก์ต๋๋ค. ๋ฌธ์ ๊ฐ ์๋ ์ฟผ๋ฆฌ์ ๋ํ ๊ณํ์ ์ธ์์ผ ํฉ๋๊น? ์ฟผ๋ฆฌ๊ฐ ์ผ๋ฐ SQL์ธ ๊ฒฝ์ฐ์๋ ๋ฌธ์ ๊ฐ ๋์ง ์์ต๋๋ค.
- ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฌ์ฉํฉ๋๋ค. ๋์ผํ SQL ํ์ผ์ ๋ค๋ฅธ ํ๋ก์ ํธ์ ๋์ด์ ๋์ผ์ธ์. ๊ทธ๋ฅ ์ค๋๋ SQL์ด๊ธฐ ๋๋ฌธ์ ๋๋ค. ๊ทธ๋ฅ ๊ณต์ ํ์ธ์.
์ ์๊ฐ์๋ ์ด ์์ด๋์ด๋ ๋งค์ฐ ๋ฉ์ง๊ณ ๋์์ ๋งค์ฐ ๊ฐ๋จํฉ๋๋ค. ๋๋ถ์ ์ด ํ๋ก์ ํธ๋ ๋ง์ ๊ฒ์ ์ป์์ต๋๋ค.
IDE ๋ฐ DB ๊ด๋ฆฌ์
๊ฐ๋จํ ์ผ์ ์ ๋ฌด๋ถํฐ ์์ํด ๋ณด๊ฒ ์ต๋๋ค. ์๋ฅผ ๋ค์ด ์คํค๋ง์์ ํ ์ด๋ธ์ ์ฐพ๊ณ ํด๋น ๊ตฌ์กฐ(์ฌ์ฉ๋๋ ์ด, ํค, ์ธ๋ฑ์ค, ์ ์ฝ ์กฐ๊ฑด ๋ฑ)๋ฅผ ์ฐ๊ตฌํ๋ ๋ฑ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ผ๋ถ ๊ฐ์ฒด๋ฅผ ๊ฒ์ํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ๋ํฝ IDE๋ ์์ DB ๊ด๋ฆฌ์์์ ๋ฌด์๋ณด๋ค๋ ์ฐ๋ฆฌ๋ ๋ฐ๋ก ์ด๋ฌํ ๊ธฐ๋ฅ์ ๊ธฐ๋ํฉ๋๋ค. ํ์ํ ์ ๋ณด๊ฐ ํฌํจ๋ ์ฐฝ์ด ๋ํ๋ ๋๊น์ง ์๋๊ฐ ๋น ๋ฅด๊ณ (ํนํ ์๊ฒฉ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ ์ฐ๊ฒฐ์ด ๋๋ฆฐ ๊ฒฝ์ฐ) XNUMX๋ถ์ ๊ธฐ๋ค๋ฆด ํ์๊ฐ ์์ผ๋ฉฐ, ๋์์ ์์ ๋ ์ ๋ณด๋ ์ ์ ํ๊ณ ๊ด๋ จ์ฑ์ด ๋์ต๋๋ค. ์บ์๋ ์ ํฌ๊ฐ ์๋๋๋ค. ๋์ฑ์ด, ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ ๋ณต์กํ๊ณ ํด์๋ก, ๊ทธ ์๊ฐ ๋ง์์๋ก ์ด๋ฅผ ์ํํ๋ ๊ฒ์ด ๋ ์ด๋ ค์์ง๋๋ค.
ํ์ง๋ง ๋ณดํต์ ๋ง์ฐ์ค๋ฅผ ๋ฒ๋ฆฌ๊ณ ์ฝ๋๋ง ์์ฑํฉ๋๋ค. "HR" ์คํค๋ง์ ์ด๋ค ํ ์ด๋ธ๊ณผ ์ด๋ค ์์ฑ์ด ํฌํจ๋์ด ์๋์ง ์์๋ด์ผ ํ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. ๋๋ถ๋ถ์ DBMS์์๋ information_schema์ ๋ค์๊ณผ ๊ฐ์ ๊ฐ๋จํ ์ฟผ๋ฆฌ๋ฅผ ํตํด ์ํ๋ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.
select table_name
, ...
from information_schema.tables
where schema = 'HR'
๋ฐ์ดํฐ๋ฒ ์ด์ค๋ง๋ค ์ด๋ฌํ ์ฐธ์กฐ ํ ์ด๋ธ์ ๋ด์ฉ์ ๊ฐ DBMS์ ๊ธฐ๋ฅ์ ๋ฐ๋ผ ๋ค๋ฆ ๋๋ค. ์๋ฅผ ๋ค์ด MySQL์ ๊ฒฝ์ฐ ๋์ผํ ์ฐธ์กฐ ์์ ์์ ์ด DBMS์ ๊ด๋ จ๋ ํ ์ด๋ธ ๋งค๊ฐ๋ณ์๋ฅผ ์ป์ ์ ์์ต๋๋ค.
select table_name
, storage_engine -- ะัะฟะพะปัะทัะตะผัะน "ะดะฒะธะถะพะบ" ("MyISAM", "InnoDB" etc)
, row_format -- ะคะพัะผะฐั ัััะพะบะธ ("Fixed", "Dynamic" etc)
, ...
from information_schema.tables
where schema = 'HR'
Oracle์ information_schema๋ฅผ ๋ชจ๋ฅด์ง๋ง ๋ค์์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
select table_name
, pct_free -- ะะธะฝะธะผัะผ ัะฒะพะฑะพะดะฝะพะณะพ ะผะตััะฐ ะฒ ะฑะปะพะบะต ะดะฐะฝะฝัั
(%)
, pct_used -- ะะธะฝะธะผัะผ ะธัะฟะพะปัะทัะตะผะพะณะพ ะผะตััะฐ ะฒ ะฑะปะพะบะต ะดะฐะฝะฝัั
(%)
, last_analyzed -- ะะฐัะฐ ะฟะพัะปะตะดะฝะตะณะพ ัะฑะพัะฐ ััะฐัะธััะธะบะธ
, ...
from all_tables
where owner = 'HR'
ClickHouse๋ ์์ธ๋ ์๋๋๋ค.
select name
, engine -- ะัะฟะพะปัะทัะตะผัะน "ะดะฒะธะถะพะบ" ("MergeTree", "Dictionary" etc)
, ...
from system.tables
where database = 'HR'
Cassandra์์๋ ๋น์ทํ ์์ ์ ์ํํ ์ ์์ต๋๋ค(ํ ์ด๋ธ ๋์ ์ปฌ๋ผํจ๋ฐ๋ฆฌ๊ฐ ์๊ณ ์คํค๋ง ๋์ ํค์คํ์ด์ค๊ฐ ์์).
select columnfamily_name
, compaction_strategy_class -- ะกััะฐัะตะณะธั ัะฑะพัะบะธ ะผััะพัะฐ
, gc_grace_seconds -- ะัะตะผั ะถะธะทะฝะธ ะผััะพัะฐ
, ...
from system.schema_columnfamilies
where keyspace_name = 'HR'
๋๋ถ๋ถ์ ๋ค๋ฅธ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฒฝ์ฐ์๋ ๋น์ทํ ์ฟผ๋ฆฌ๊ฐ ๋์ฌ ์ ์์ต๋๋ค(Mongo๋
๋ฌผ๋ก ์ด๋ฐ ๋ฐฉ์์ผ๋ก ํ
์ด๋ธ๋ฟ๋ง ์๋๋ผ ์ผ๋ฐ์ ์ธ ๋ชจ๋ ๊ฐ์ฒด์ ๋ํ ์ ๋ณด๋ฅผ ์ป์ ์ ์์ต๋๋ค. ๋๋๋ก ์น์ ํ ์ฌ๋๋ค์ Habra ๊ธฐ์ฌ ์๋ฆฌ์ฆ "PostgreSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฌธ์ํ ๊ธฐ๋ฅ"(
๊ฒฐ๊ณผ์ ์ผ๋ก ์ด ๊ฐ์ฒด ํ์ ๋ฐ ๊ฒ์ ๋ฐฉ๋ฒ์ ํจ์ฌ ๋ ์ ์ฐํ๊ณ ๋ง์ ์๊ฐ์ ์ ์ฝํ๋ฉฐ ํ์ฌ ํ์ํ ํ์์ผ๋ก ์ ๋ณด๋ฅผ ์ ํํ๊ฒ ์ป์ ์ ์์ต๋๋ค(์๋ฅผ ๋ค์ด ๊ฒ์๋ฌผ์ ์ค๋ช
๋ ๋๋ก).
๊ฐ์ฒด ์์
ํ์ํ ๋ฌผ๊ฑด์ ์ฐพ์ ์ฐ๊ตฌํ ํ์๋ ๊ทธ ๋ฌผ๊ฑด์ ๊ฐ์ง๊ณ ๋ญ๊ฐ ์ ์ฉํ ์ผ์ ํ ์ฐจ๋ก์ ๋๋ค. ๋น์ฐํ ํค๋ณด๋์์ ์๊ฐ๋ฝ์ ๋ผ์ง ์๊ณ ๋ ๊ฐ๋ฅํฉ๋๋ค.
๋จ์ํ ํ ์ด๋ธ์ ์ญ์ ํ๋ฉด ๊ฑฐ์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋์ผํ๊ฒ ๋ณด์ธ๋ค๋ ๊ฒ์ ๋น๋ฐ์ด ์๋๋๋ค.
drop table hr.persons
๊ทธ๋ฌ๋ ํ
์ด๋ธ์ ๋ง๋ค๋ฉด ๋์ฑ ํฅ๋ฏธ๋ก์์ง๋๋ค. ๋๋ถ๋ถ์ NoSQL์ ํฌํจํ์ฌ ๊ฑฐ์ ๋ชจ๋ DBMS๋ ํ ๊ฐ์ง ํ์ ๋๋ ๋ค๋ฅธ ํ์์ผ๋ก "ํ
์ด๋ธ์ ์์ฑ"ํ ์ ์์ผ๋ฉฐ ์ฃผ์ ๋ถ๋ถ(์ด๋ฆ, ์ด ๋ชฉ๋ก, ๋ฐ์ดํฐ ์ ํ)์ ์ฝ๊ฐ ๋ค๋ฅผ ์ ์์ง๋ง ๊ธฐํ ์ธ๋ถ ์ฌํญ์ ๊ทน์ ์ผ๋ก ๋ค๋ฅผ ์ ์์ผ๋ฉฐ ์ํฉ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค. ํน์ DBMS์ ๋ด๋ถ ์ฅ์น ๋ฐ ๊ธฐ๋ฅ. ์ ๊ฐ ๊ฐ์ฅ ์ข์ํ๋ ์๋ Oracle ๋ฌธ์์ "create table" ๊ตฌ๋ฌธ์ ๋ํ "naked" BNF๋ง ์๋ค๋ ๊ฒ์
๋๋ค.
๋ํ ๋ง์ DBMS์๋ ๋ค๋ฅธ DBMS์์๋ ์ฌ์ฉํ ์ ์๋ ๊ณ ์ ํ ํน์ ์ ํ์ ๊ฐ์ฒด๊ฐ ์์ต๋๋ค. ๋ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ์ฒด๋ฟ๋ง ์๋๋ผ DBMS ์์ฒด์์๋ ์์ ์ ์ํํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ํ๋ก์ธ์ค๋ฅผ "์ข ๋ฃ"ํ๊ณ , ์ผ๋ถ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ํ๋ณดํ๊ณ , ์ถ์ ์ ํ์ฑํํ๊ณ , "์ฝ๊ธฐ ์ ์ฉ" ๋ชจ๋๋ก ์ ํํ๋ ๋ฑ์ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
์ด์ ์ข ๊ทธ๋ ค๋ณด์
๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์์ ์ค ํ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ฐ์ฒด๋ก ๋ค์ด์ด๊ทธ๋จ์ ์์ฑํ๊ณ ์๋ฆ๋ค์ด ๊ทธ๋ฆผ์์ ๊ฐ์ฒด์ ๊ฐ์ฒด ๊ฐ์ ์ฐ๊ฒฐ์ ํ์ธํ๋ ๊ฒ์ ๋๋ค. ๊ฑฐ์ ๋ชจ๋ ๊ทธ๋ํฝ IDE, ๋ณ๋์ "๋ช ๋ น์ค" ์ ํธ๋ฆฌํฐ, ํน์ ๊ทธ๋ํฝ ๋๊ตฌ ๋ฐ ๋ชจ๋ธ๋ฌ๊ฐ ์ด๋ฅผ ์ํํ ์ ์์ต๋๋ค. ๊ทธ๋ค์ "๊ฐ๋ฅํ ํ ์ต์ ์ ๋คํด" ๋ฌด์ธ๊ฐ๋ฅผ ๊ทธ๋ ค์ค ๊ฒ์ด๋ฉฐ ๊ตฌ์ฑ ํ์ผ์ ๋ช ๊ฐ์ง ๋งค๊ฐ๋ณ์๋ ์ธํฐํ์ด์ค์ ํ์ธ๋์ ํตํด์๋ง ์ด ํ๋ก์ธ์ค์ ์ฝ๊ฐ์ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค.
ํ์ง๋ง ์ด ๋ฌธ์ ๋ ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ฉด ํจ์ฌ ๋ ๊ฐ๋จํ๊ณ ์ ์ฐํ๋ฉฐ ์ฐ์ํ๊ฒ ํด๊ฒฐํ ์ ์์ต๋๋ค. ๋ณต์กํ ๋ค์ด์ด๊ทธ๋จ์ ์์ฑํ๊ธฐ ์ํด ์ฐ๋ฆฌ๋ ์ฌ๋ฌ ๊ฐ์ง ์ ๋ฌธ์ ์ธ ๋งํฌ์ ์ธ์ด(DOT, GraphML ๋ฑ)์ ์ด๋ฌํ ์ง์นจ์ ์ฝ๊ณ ๋ค์ํ ํ์์ผ๋ก ์๊ฐํํ ์ ์๋ ๋ค์ํ ์ ํ๋ฆฌ์ผ์ด์ (GraphViz, PlantUML, Mermaid)์ ๋ณด์ ํ๊ณ ์์ต๋๋ค. . ๊ธ์, ์ฐ๋ฆฌ๋ ๊ฐ์ฒด์ ๊ฐ์ฒด ๊ฐ์ ์ฐ๊ฒฐ์ ๋ํ ์ ๋ณด๋ฅผ ์ป๋ ๋ฐฉ๋ฒ์ ์ด๋ฏธ ์๊ณ ์์ต๋๋ค.
PlantUML์ ์ฌ์ฉํ์ฌ ์ด๊ฒ์ด ์ด๋ป๊ฒ ๋ณด์ผ ์ ์๋์ง์ ๋ํ ์์ ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
select '@startuml'||chr(10)||'hide methods'||chr(10)||'hide stereotypes' union all
select distinct ccu.table_name || ' --|> ' ||
tc.table_name as val
from table_constraints as tc
join key_column_usage as kcu
on tc.constraint_name = kcu.constraint_name
join constraint_column_usage as ccu
on ccu.constraint_name = tc.constraint_name
where tc.constraint_type = 'FOREIGN KEY'
and tc.table_name ~ '.*' union all
select '@enduml'
๊ทธ๋ฆฌ๊ณ ์กฐ๊ธ๋ง ์๋ํด ๋ณด๋ฉด
SQL ์ฟผ๋ฆฌ๋ ์กฐ๊ธ ๋ ๋ณต์กํฉ๋๋ค.
-- ะจะฐะฟะบะฐ
select '@startuml
!define Table(name,desc) class name as "desc" << (T,#FFAAAA) >>
!define primary_key(x) <b>x</b>
!define unique(x) <color:green>x</color>
!define not_null(x) <u>x</u>
hide methods
hide stereotypes'
union all
-- ะขะฐะฑะปะธัั
select format('Table(%s, "%s n information about %s") {'||chr(10), table_name, table_name, table_name) ||
(select string_agg(column_name || ' ' || upper(udt_name), chr(10))
from information_schema.columns
where table_schema = 'public'
and table_name = t.table_name) || chr(10) || '}'
from information_schema.tables t
where table_schema = 'public'
union all
-- ะกะฒัะทะธ ะผะตะถะดั ัะฐะฑะปะธัะฐะผะธ
select distinct ccu.table_name || ' "1" --> "0..N" ' || tc.table_name || format(' : "A %s may haven many %s"', ccu.table_name, tc.table_name)
from information_schema.table_constraints as tc
join information_schema.key_column_usage as kcu on tc.constraint_name = kcu.constraint_name
join information_schema.constraint_column_usage as ccu on ccu.constraint_name = tc.constraint_name
where tc.constraint_type = 'FOREIGN KEY'
and ccu.constraint_schema = 'public'
and tc.table_name ~ '.*'
union all
-- ะะพะดะฒะฐะป
select '@enduml'
์์ธํ ์ดํด๋ณด๋ฉด ๋ง์ ์๊ฐํ ๋๊ตฌ๋ ์ ์ฌํ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ฌ์ค, ์ด๋ฌํ ์์ฒญ์ ์ผ๋ฐ์ ์ผ๋ก ๋งค์ฐ ์ฌ๊ฐํฉ๋๋ค.
์ธก์ ํญ๋ชฉ ๋ฐ ๋ชจ๋ํฐ๋ง
์ ํต์ ์ผ๋ก ๋ณต์กํ ์ฃผ์ ์ธ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง์ผ๋ก ๋์ด๊ฐ๊ฒ ์ต๋๋ค. ๋๋ "๋ด ์น๊ตฌ ์ค ํ ๋ช "์ด ๋์๊ฒ ๋ค๋ ค์ค ์์ ์คํ๋ฅผ ๊ธฐ์ตํฉ๋๋ค. ๋ ๋ค๋ฅธ ํ๋ก์ ํธ์๋ ๊ฐ๋ ฅํ DBA๊ฐ ์ด๊ณ ์์๋๋ฐ, ๊ทธ๋ฅผ ๊ฐ์ธ์ ์ผ๋ก ์๊ณ ์๊ฑฐ๋ ์ง์ ๋ณธ ์ ์ด ์๋ ๊ฐ๋ฐ์๋ ๊ฑฐ์ ์์์ต๋๋ค(์๋ฌธ์ ๋ฐ๋ฅด๋ฉด ๊ทธ๊ฐ ๋ค์ ๊ฑด๋ฌผ ์ด๋๊ฐ์์ ์ผํ๋ค๋ ์ฌ์ค์๋ ๋ถ๊ตฌํ๊ณ ). X์๊ฐ์ ๋ํ ์๋งค์ ์ฒด์ ์์ฐ ์์คํ ์ด ๋ค์ "๋ถ์พ"ํด์ง๊ธฐ ์์ํ์ ๊ทธ๋ ์กฐ์ฉํ Oracle Enterprise Manager์ ๊ทธ๋ํ ์คํฌ๋ฆฐ์ท์ ๋ณด๋๊ณ , ๊ฑฐ๊ธฐ์์ ๊ทธ๋ "์ดํด์ฑ"์ ์๋ฏธํ๋ ๋นจ๊ฐ์ ๋ง์ปค๋ก ์ค์ํ ๋ถ๋ถ์ ์ฃผ์ ๊น๊ฒ ๊ฐ์กฐํ์ต๋๋ค( ๊ฐ๋ณ๊ฒ ๋งํ๋ฉด ๋ณ๋ก ๋์์ด ๋์ง ์์์ต๋๋ค.) ๊ทธ๋ฆฌ๊ณ ์ด 'ํฌํ ์นด๋'๋ฅผ ๋ฐํ์ผ๋ก ์น๋ฃ๋ฅผ ํด์ผ ํ์ด์. ๋์์, ๋๊ตฌ๋ ๊ท์คํ(๋ ๊ฐ์ง ์๋ฏธ์์) Enterprise Manager์ ์ก์ธ์คํ ์ ์์์ต๋๋ค. ์์คํ ์ด ๋ณต์กํ๊ณ ๋น์ฉ์ด ๋ง์ด ๋ค๊ธฐ ๋๋ฌธ์ ๊ฐ์๊ธฐ "๊ฐ๋ฐ์๋ค์ด ๋ญ๊ฐ์ ๊ฑธ๋ ค์ ๋ชจ๋ ๊ฒ์ ๋ง๊ฐ๋จ๋ฆฝ๋๋ค." ์ด์ ๊ฐ๋ฐ์๋ค์ ๋ธ๋ ์ดํฌ์ ์์น์ ์์ธ์ '๊ฒฝํ์ ์ผ๋ก' ์ฐพ์๋ด๊ณ ํจ์น๋ฅผ ๊ณต๊ฐํ๋ค. ๊ฐ๊น์ด ์์ผ ๋ด์ DBA์ ์ํ์ ์ธ ํธ์ง๊ฐ ๋ค์ ๋์ฐฉํ์ง ์์ผ๋ฉด ๋ชจ๋ ์ฌ๋์ ์๋์ ํ์จ์ ์ฌ๊ณ ํ์ฌ ์์ ์ผ๋ก ๋์๊ฐ ๊ฒ์ ๋๋ค(์ ํธ์ง๊ฐ ์ฌ ๋๊น์ง).
๊ทธ๋ฌ๋ ๋ชจ๋ํฐ๋ง ํ๋ก์ธ์ค๋ ๋์ฑ ์ฌ๋ฏธ์๊ณ ์น๊ทผํด ๋ณด์ผ ์ ์์ผ๋ฉฐ, ๊ฐ์ฅ ์ค์ํ๊ฒ๋ ๋ชจ๋ ์ฌ๋์ด ์ ๊ทผ ๊ฐ๋ฅํ๊ณ ํฌ๋ช
ํ๊ฒ ๋ณด์ผ ์ ์์ต๋๋ค. ์ต์ํ ๊ธฐ๋ณธ ๋ชจ๋ํฐ๋ง ์์คํ
์ ์ถ๊ฐ๋๋ ๊ธฐ๋ณธ ๋ถ๋ถ์
๋๋ค(ํ์คํ ์ ์ฉํ๊ณ ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๋์ฒดํ ์ ์์). ๋ชจ๋ DBMS๋ ํ์ฌ ์ํ์ ์ฑ๋ฅ์ ๋ํ ์ ๋ณด๋ฅผ ๋ฌด๋ฃ๋ก ๊ณต์ ํ ์ ์์ต๋๋ค. ๋์ผํ "ํผ๋ฌป์" Oracle DB์์๋ ํ๋ก์ธ์ค ๋ฐ ์ธ์
์์ ๋ฒํผ ์บ์ ์ํ์ ์ด๋ฅด๊ธฐ๊น์ง ์ฑ๋ฅ์ ๋ํ ๊ฑฐ์ ๋ชจ๋ ์ ๋ณด๋ฅผ ์์คํ
๋ทฐ์์ ์ป์ ์ ์์ต๋๋ค(์:
๋ฐ๋ผ์ ์ฌ์ฉ์ ์ ์ SQL ์ฟผ๋ฆฌ๋ฅผ ์ํํ ์ ์๋ ์ผ์ข
์ ๋ฉํธ๋ฆญ ์์ง๊ธฐ(Telegraf, Metricbeat, Collectd), ์ด๋ฌํ ๋ฉํธ๋ฆญ์ ์ ์ฅ(InfluxDB, Elasticsearch, Timescaledb) ๋ฐ ์๊ฐํ ๋๊ตฌ(Grafana, Kibana)๋ฅผ ์ฌ์ฉํ๋ฉด ์๋นํ ์ฝ๊ฒ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ค๋ฅธ ์์คํ
์ ๋ฐ์ ์งํ(์๋ฅผ ๋ค์ด ์ ํ๋ฆฌ์ผ์ด์
์๋ฒ, OS ๋ฑ์์ ํ๋)์ ๊ธด๋ฐํ๊ฒ ํตํฉ๋๋ ์ ์ฐํ ๋ชจ๋ํฐ๋ง ์์คํ
์
๋๋ค. ์๋ฅผ ๋ค์ด, ์ด๋ InfluxDB + Grafana ์กฐํฉ๊ณผ ์ก์ธ์คํ ์ ์๋ ์์คํ
๋ทฐ์ ๋ํ ์ฟผ๋ฆฌ ์ธํธ๋ฅผ ์ฌ์ฉํ๋ pgwatch2์์ ์ํ๋ฉ๋๋ค.
์ ์ฒด๋ก
์ด๋ ์ผ๋ฐ SQL ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ์ํํ ์ ์๋ ์์ ์ ๋๋ต์ ์ธ ๋ชฉ๋ก์ผ ๋ฟ์ ๋๋ค. ๋ ๋ง์ ์ฉ๋๋ฅผ ์ฐพ์ ์ ์์ ๊ฒ์ด๋ผ๊ณ ํ์ ํฉ๋๋ค. ๋๊ธ์ ์์ฑํด ์ฃผ์ธ์. ๊ทธ๋ฆฌ๊ณ ๋ค์๋ฒ์๋ ์ด ๋ชจ๋ ๊ฒ์ ์๋ํํ๊ณ CI/CD ํ์ดํ๋ผ์ธ์ ํฌํจ์ํค๋ ๋ฐฉ๋ฒ(๊ทธ๋ฆฌ๊ณ ๊ฐ์ฅ ์ค์ํ ์ด์ )์ ๋ํด ์ด์ผ๊ธฐํ๊ฒ ์ต๋๋ค.
์ถ์ฒ : habr.com