LIMIT ํ์ด์ง, DATE_FORMAT, ON DUPLICATE KEY UPDATE, GROUP_CONCAT, ์ธ๋ฑ์ค ํํธ, ์๋์ฐ ํจ์, EXPLAIN ๋ฐ ํธ๋์ญ์
๋ฝ ๋ ํผ๋ฐ์ค
## 1. ํ์ด์ง ์ฟผ๋ฆฌ (LIMIT & OFFSET)
```sql
-- 1. LIMIT count OFFSET offset (๊ฐ์ฅ ๊ฐ๋
์ฑ ๋์ ํ์ค)
SELECT id, username, email
FROM users
ORDER BY id DESC
LIMIT 10 OFFSET 20; -- 21๋ฒ์งธ๋ถํฐ 10๊ฑด ์กฐํ
-- 2. LIMIT offset, count (์ถ์ฝํ - ์์ ์ฃผ์: offset ๋จผ์ !)
SELECT id, username
FROM users
ORDER BY id DESC
LIMIT 20, 10;
-- ๐ก ๋์ฉ๋ ํ์ด์ง ์ฑ๋ฅ ์ต์ ํ (์ปค๋ฒ๋ง ์ธ๋ฑ์ค + No Offset ๊ธฐ๋ฒ)
-- WHERE id < ๋ง์ง๋ง๋ณธ_ID ORDER BY id DESC LIMIT 10;
```
## 2. ๋ ์ง & ์๊ฐ ํจ์ (Date & Time)
```sql
-- ํ์ฌ ์ผ์
SELECT NOW(), CURRENT_TIMESTAMP(), CURDATE(), CURTIME();
-- 1. ํฌ๋งท ๋ณํ (DATE_FORMAT / STR_TO_DATE)
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') AS formatted_now;
SELECT STR_TO_DATE('2026-09-26 14:30:00', '%Y-%m-%d %H:%i:%s');
-- 2. ๋ ์ง ๊ฐ๊ฐ (DATE_ADD / DATE_SUB)
SELECT DATE_ADD(NOW(), INTERVAL 7 DAY) AS ์ผ์ฃผ์ผ_ํ;
SELECT DATE_ADD(NOW(), INTERVAL 1 MONTH) AS ํ๋ฌ_ํ;
SELECT DATE_SUB(NOW(), INTERVAL 1 HOUR) AS ํ์๊ฐ_์ ;
-- 3. ๋ ์ง ์ฐจ์ด ๊ณ์ฐ (DATEDIFF / TIMESTAMPDIFF)
SELECT DATEDIFF('2026-09-26', '2026-09-01'); -- 25 (์ผ ๋จ์ ์ฐจ์ด)
SELECT TIMESTAMPDIFF(MINUTE, '2026-09-26 12:00:00', NOW()); -- ๋ถ ๋จ์ ์ฐจ์ด
```
## 3. NULL ์ฒ๋ฆฌ & ์กฐ๊ฑด ๋ถ๊ธฐ (IFNULL & IF)
```sql
-- 1. IFNULL: null์ด๋ฉด ๋์ฒด๊ฐ ๋ฐํ
SELECT IFNULL(point, 0) FROM users;
-- 2. IF: 3ํญ ์ฐ์ฐ์ ์กฐ๊ฑด๋ฌธ (์กฐ๊ฑด, ์ฐธ๊ฐ, ๊ฑฐ์ง๊ฐ)
SELECT IF(score >= 80, 'ํฉ๊ฒฉ', '๋ถํฉ๊ฒฉ') FROM exam_results;
-- 3. COALESCE: null์ด ์๋ ์ฒซ ๋ฒ์งธ ๊ฐ ๋ฐํ
SELECT COALESCE(tel, mobile, email, '์์') FROM contacts;
-- 4. CASE WHEN ์กฐ๊ฑด ๋ถ๊ธฐ
SELECT
CASE
WHEN role = 'ADMIN' THEN '๊ด๋ฆฌ์'
WHEN role = 'USER' THEN '์ผ๋ฐํ์'
ELSE '๊ฒ์คํธ'
END AS role_name
FROM users;
```
## 4. ๋ฌธ์์ด ์กฐ์ & ๊ทธ๋ฃน ํฉ์น๊ธฐ (GROUP_CONCAT)
```sql
-- 1. ๋ฌธ์์ด ์ฐ๊ฒฐ (CONCAT & CONCAT_WS)
SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM users;
SELECT CONCAT_WS('-', '010', '1234', '5678'); -- ๊ตฌ๋ถ์ ์๋ ์ฝ์
('010-1234-5678')
-- 2. GROUP_CONCAT: ๊ทธ๋ฃน๋ณ ์ฌ๋ฌ ํ ๋ฌธ์์ด์ ํ ์ค๋ก ํฉ์น๊ธฐ
SELECT dept_id,
GROUP_CONCAT(name ORDER BY name ASC SEPARATOR ', ') AS member_names
FROM employees
GROUP BY dept_id;
-- 3. ๋ฌธ์์ด ์๋ฅด๊ธฐ & ๊ธธ์ด
SELECT SUBSTRING('MySQL', 1, 3); -- 'MyS' (1๋ถํฐ ์์)
SELECT CHAR_LENGTH('ํ๊ธ'); -- 2 (๊ธ์์)
SELECT LENGTH('ํ๊ธ'); -- 6 (UTF-8 ๋ฐ์ดํธ์)
```
## 5. Upsert: ON DUPLICATE KEY UPDATE
```sql
-- 1. MySQL 8.0.19 ์ด์ ์ต์ ๊ถ์ฅ ๋ฌธ๋ฒ (AS new_val ๋ณ์นญ ํ์ฉ)
INSERT INTO user_points (user_id, point, updated_at)
VALUES (101, 50, NOW()) AS new_row
ON DUPLICATE KEY UPDATE
point = point + new_row.point,
updated_at = new_row.updated_at;
-- 2. ๋ ๊ฑฐ์ ๋ฌธ๋ฒ (VALUES(์ปฌ๋ผ๋ช
) - 8.0.20๋ถํฐ Deprecated)
INSERT INTO user_points (user_id, point)
VALUES (101, 50)
ON DUPLICATE KEY UPDATE
point = point + VALUES(point);
```
## 6. AUTO_INCREMENT & ๋ฐ๊ธ ID ํ์ธ
```sql
CREATE TABLE boards (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL
);
INSERT INTO boards (title) VALUES ('์ฒซ ๋ฒ์งธ ๊ณต์ง');
-- ๐ก ํ์ฌ ์ธ์
์์ ๋ฐฉ๊ธ ์์ฑ๋ AUTO_INCREMENT ID ํ์ธ
SELECT LAST_INSERT_ID();
```
## 7. ์ธ๋ฑ์ค ํํธ (USE / FORCE / IGNORE INDEX)
```sql
-- 1. ํน์ ์ธ๋ฑ์ค ์ฌ์ฉ ๊ถ์ฅ (USE INDEX)
SELECT * FROM orders USE INDEX (idx_order_date)
WHERE order_date >= '2026-01-01';
-- 2. ํน์ ์ธ๋ฑ์ค ๊ฐ์ ์ ์ฉ (FORCE INDEX: ๋น์ฉ ๊ณ์ฐ ๋ฌด์)
SELECT * FROM users FORCE INDEX (idx_users_email)
WHERE email = 'test@example.com';
-- 3. ํน์ ์ธ๋ฑ์ค ๋ฌด์ (ํ์ค์บ ์ ๋ ์)
SELECT * FROM products IGNORE INDEX (idx_prod_category)
WHERE category = 'SALE';
```
## 8. ์๋์ฐ ํจ์ & CTE (MySQL 8.0+)
```sql
-- 1. ์์ ๋ฐ ๋์ ํฉ
SELECT
emp_id, dept_id, salary,
ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS dept_rank,
SUM(salary) OVER (PARTITION BY dept_id) AS dept_total
FROM employees;
-- 2. ๊ณ์ธตํ ์ฌ๊ท ์ฟผ๋ฆฌ (WITH RECURSIVE)
WITH RECURSIVE CategoryPath AS (
SELECT id, parent_id, name, CAST(name AS CHAR(200)) AS path
FROM categories WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.parent_id, c.name, CONCAT(cp.path, ' > ', c.name)
FROM categories c
INNER JOIN CategoryPath cp ON c.parent_id = cp.id
)
SELECT * FROM CategoryPath;
```
## 9. ์คํ๊ณํ ๋ถ์ (EXPLAIN & FORMAT=TREE)
```sql
-- 1. ๊ธฐ๋ณธ ์คํ๊ณํ (type, possible_keys, key, rows ์ฒดํฌ)
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
-- ๐ก type ์ฐ์ ์์: const > eq_ref > ref > range > index > ALL (ALL์ ํํ
์ด๋ธ์ค์บ)
-- 2. MySQL 8.0 ์ ๊ท ํธ๋ฆฌ ํฌ๋งท ์คํ๊ณํ (์ค์ ๋น์ฉ๊ณผ ์กฐ์ธ ์๊ณ ๋ฆฌ์ฆ ์ง๊ด์ ํ์
)
EXPLAIN FORMAT=TREE
SELECT * FROM users u JOIN orders o ON u.id = o.user_id WHERE u.age > 20;
-- 3. ์ค์ ์คํ ํต๊ณ ์ธก์ (EXPLAIN ANALYZE)
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
```
## 10. ์ธ์
๊ด๋ฆฌ & ํธ๋์ญ์
๋ฝ (FOR UPDATE)
```sql
-- 1. ๋น๊ด์ ๋ฝ: ๋ฐฐํ์ ์ฝ๊ธฐ ๋ฝ (๋์ ์์ ๋ฐฉ์ง)
START TRANSACTION;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- ํ ํธ๋์ญ์
๋๊ธฐ
UPDATE accounts SET balance = balance - 1000 WHERE id = 1;
COMMIT;
-- 2. ํ์ฌ ์คํ ์ค์ธ ์ฟผ๋ฆฌ ๋ชฉ๋ก ํ์ธ
SHOW FULL PROCESSLIST;
-- 3. ํน์ ์ฟผ๋ฆฌ/์ธ์
๊ฐ์ ์ข
๋ฃ (KILL id)
-- KILL 4821;
-- 4. InnoDB ๋ฝ ์ํ ๋ฐ ํธ๋์ญ์
๋ชจ๋ํฐ๋ง (8.0+)
SELECT * FROM performance_schema.data_locks;
SELECT * FROM performance_schema.data_lock_waits;
```
์๊ฒฌ ๋ฐ ์ง๋ฌธ
0์์ง ๋ฑ๋ก๋ ์๊ฒฌ์ด ์์ต๋๋ค. ์ฒซ ๋ฒ์งธ ๋๊ธ์ ๋จ๊ฒจ๋ณด์ธ์!
๋๊ธ ์์
๋๊ธ ์ญ์