{"data":[{"id":109255,"title":"[Vibe Coding Th\u1ef1c Chi\u1ebfn #11] \u0110\u01b0a Web Ra Bi\u1ec3n L\u1edbn: Tr\u1ecf T\u00ean Mi\u1ec1n Ri\u00eang, C\u1ea5p SSL Let's Encrypt T\u1ef1 \u0110\u1ed9ng & C\u1ea5u H\u00ecnh Token Sharing \u0110a T\u00ean Mi\u1ec1n!","slug":"wd43ExrKLX9","url":"https:\/\/viblo.asia\/p\/vibe-coding-thuc-chien-11-dua-web-ra-bien-lon-tro-ten-mien-rieng-cap-ssl-lets-encrypt-tu-dong-cau-hinh-token-sharing-da-ten-mien-wd43ExrKLX9","user_id":212424,"moderation":null,"transliterated":"vibe-coding-thuc-chien-11-dua-web-ra-bien-lon-tro-ten-mien-rieng-cap-ssl-lets-encrypt-tu-dong-cau-hinh-token-sharing-da-ten-mien","contents_short":"T\u00e1c gi\u1ea3: Lee\nSeries: Vibe Coding Th\u1ef1c Chi\u1ebfn C\u00f9ng EzyPlatform (#11)\nH\u1ea1 t\u1ea7ng th\u1ef1c nghi\u1ec7m: VPS Ubuntu 22.04 LTS (157.66.47.xxx) | Domain Admin: https:\/\/1576647xxx-admin.interdata.io.vn\nB\u1ed9 c\u00f4ng c\u1ee5: VS Code + Extension youngmonkeys.ezyarticle + Claude Code CLI \/ Codex + Cloudflare DNS + EzySupport SSL\n\n\u1ede b\u00e0i vi\u1ebft s\u1ed1 #10, ch\u00fang ta \u0111\u00e3 kh\u00e9p k\u00edn to\u00e0n b\u1ed9 chu tr\u00ecnh b\u00e1n h\u00e0ng th\u1ef1c chi\u1ebfn: kh\u00e1ch v\u1eeba b\u1ea5m \u0111\u1eb7t b...","contents":"> **T\u00e1c gi\u1ea3:** Lee  \n> **Series:** Vibe Coding Th\u1ef1c Chi\u1ebfn C\u00f9ng EzyPlatform (#11)  \n> **H\u1ea1 t\u1ea7ng th\u1ef1c nghi\u1ec7m:** VPS Ubuntu 22.04 LTS (`157.66.47.xxx`) | Domain Admin: `https:\/\/1576647xxx-admin.interdata.io.vn`  \n> **B\u1ed9 c\u00f4ng c\u1ee5:** VS Code + Extension `youngmonkeys.ezyarticle` + Claude Code CLI \/ Codex + Cloudflare DNS + EzySupport SSL  \n\n---\n\n\u1ede [b\u00e0i vi\u1ebft s\u1ed1 #10](https:\/\/viblo.asia\/p\/vibe-coding-thuc-chien-10-tu-dong-hoa-sau-ban-hang-tich-hop-webhook-ban-don-sang-telegram-gui-email-tuc-thi-Nj4vgOmdJ6r), ch\u00fang ta \u0111\u00e3 kh\u00e9p k\u00edn to\u00e0n b\u1ed9 chu tr\u00ecnh b\u00e1n h\u00e0ng th\u1ef1c chi\u1ebfn: kh\u00e1ch v\u1eeba b\u1ea5m \u0111\u1eb7t b\u00e1nh tr\u00ean website, Telegram nh\u00f3m n\u1ed9i b\u1ed9 c\u1ee7a ch\u1ee7 shop l\u1eadp t\u1ee9c n\u1ed5 \"ting ting\" sau 1.2s v\u00e0 h\u00f2m th\u01b0 kh\u00e1ch h\u00e0ng nh\u1eadn ngay h\u00f3a \u0111\u01a1n \u0111i\u1ec7n t\u1eed HTML sang tr\u1ecdng.\n\nTh\u1ebf nh\u01b0ng, n\u1ebfu b\u1ea1n g\u1eedi cho kh\u00e1ch h\u00e0ng m\u1ed9t \u0111\u01b0\u1eddng link d\u1ea1ng \u0111\u1ecba ch\u1ec9 IP th\u00f4 `http:\/\/157.66.47.xxx` ho\u1eb7c m\u1ed9t subdomain k\u1ef9 thu\u1eadt d\u00e0i ngo\u1eb1ng, tr\u00ecnh duy\u1ec7t s\u1ebd l\u1eadp t\u1ee9c hi\u1ec7n c\u1ea3nh b\u00e1o \u0111\u1ecf l\u00f2m: **\"Not Secure - K\u1ebft n\u1ed1i c\u1ee7a b\u1ea1n kh\u00f4ng an to\u00e0n\"**. \n\nCh\u1eafc ch\u1eafn 99% kh\u00e1ch h\u00e0ng s\u1ebd \u0111\u00f3ng tab ngay l\u1eadp t\u1ee9c v\u00e0 kh\u00f4ng bao gi\u1edd d\u00e1m nh\u1eadp th\u00f4ng tin mua s\u1eafm!\n\n> *\"L\u00e0m sao \u0111\u1ec3 tr\u1ecf t\u00ean mi\u1ec1n th\u01b0\u01a1ng hi\u1ec7u ri\u00eang (`lepetitbakery.vn`) v\u1ec1 VPS? L\u00e0m sao \u0111\u1ec3 k\u00edch ho\u1ea1t \u1ed5 kh\u00f3a xanh HTTPS (SSL Let's Encrypt) mi\u1ec5n ph\u00ed m\u00e0 kh\u00f4ng c\u1ea7n ph\u1ea3i SSH v\u00e0o m\u00e1y ch\u1ee7 g\u00f5 l\u1ec7nh certbot \u0111au \u0111\u1ea7u? V\u00e0 t\u1ea1i sao khi \u0111\u1ed5i t\u00ean mi\u1ec1n th\u00ec m\u00e0n h\u00ecnh Preview trong VS Code l\u1ea1i b\u1ecb tr\u1eafng tinh do l\u1ed7i Cookie?\"*\n\nTrong b\u00e0i vi\u1ebft s\u1ed1 #11 n\u00e0y, m\u00ecnh s\u1ebd c\u00f9ng b\u1ea1n gi\u1ea3i quy\u1ebft d\u1ee9t \u0111i\u1ec3m c\u00e1c b\u00e0i to\u00e1n h\u1ea1 t\u1ea7ng Production: **Tr\u1ecf DNS si\u00eau t\u1ed1c \u2794 C\u1ea5p SSL Let's Encrypt 1-click qua EzySupport \u2794 Kh\u00f3a ch\u1eb7t c\u01a1 ch\u1ebf Token Sharing \u0111a t\u00ean mi\u1ec1n \u2794 B\u00e0n giao website s\u1eb5n s\u00e0ng \u0111\u00f3n h\u00e0ng ng\u00e0n kh\u00e1ch h\u00e0ng!**\n\n---\n\n## 1. Ki\u1ebfn tr\u00fac T\u00ean Mi\u1ec1n & C\u01a1 ch\u1ebf C\u1ea5p SSL T\u1ef1 \u0110\u1ed9ng Tr\u00ean EzyPlatform\n\nNhi\u1ec1u anh em dev khi nghe \u0111\u1ebfn vi\u1ec7c tr\u1ecf t\u00ean mi\u1ec1n v\u00e0 c\u1ea5p ch\u1ee9ng ch\u1ec9 SSL th\u01b0\u1eddng r\u1ea5t ng\u1ea1i v\u00ec ngh\u0129 \u0111\u1ebfn c\u1ea3nh ph\u1ea3i SSH v\u00e0o Ubuntu, c\u00e0i \u0111\u1eb7t `certbot`, vi\u1ebft file c\u1ea5u h\u00ecnh VirtualHost Nginx, r\u1ed3i lo l\u1eafng ch\u1ee9ng ch\u1ec9 h\u1ebft h\u1ea1n sau 90 ng\u00e0y l\u00e0m s\u1eadp web.\n\nV\u1edbi h\u1ec7 sinh th\u00e1i EzyPlatform, plugin **EzySupport** \u0111\u00e3 t\u00edch h\u1ee3p s\u1eb5n ACME Client \u0111\u1ec3 t\u1ef1 \u0111\u1ed9ng h\u00f3a 100% quy tr\u00ecnh n\u00e0y:\n\n![Ki\u1ebfn Tr\u00fac \u0110i\u1ec1u H\u01b0\u1edbng T\u00ean Mi\u1ec1n Ri\u00eang v\u00e0 C\u1ea5p SSL Let's Encrypt](https:\/\/images.viblo.asia\/dd9c053f-c5c8-47cb-a3b0-9c7c2fbc648d.png)\n*Lu\u1ed3ng ph\u00e2n gi\u1ea3i: Kh\u00e1ch g\u00f5 t\u00ean mi\u1ec1n \u2794 Cloudflare DNS ph\u00e2n gi\u1ea3i IP VPS \u2794 EzySupport c\u1ea5p SSL 1-click \u2794 Nginx Reverse Proxy ph\u00e2n lu\u1ed3ng an to\u00e0n.*\n\n### Lu\u1ed3ng \u0111i\u1ec1u h\u01b0\u1edbng chuy\u00ean nghi\u1ec7p gi\u1eefa 2 t\u1ea7ng:\n* **T\u00ean mi\u1ec1n ch\u00ednh (`lepetitbakery.vn`):** D\u00e0nh ri\u00eang cho kh\u00e1ch h\u00e0ng gh\u00e9 th\u0103m, xem th\u1ef1c \u0111\u01a1n v\u00e0 \u0111\u1eb7t b\u00e1nh.\n* **Subdomain qu\u1ea3n tr\u1ecb (`admin.lepetitbakery.vn` ho\u1eb7c subdomain k\u1ef9 thu\u1eadt):** D\u00e0nh ri\u00eang cho qu\u1ea3n tr\u1ecb vi\u00ean v\u00e0 dev qu\u1ea3n l\u00fd d\u1eef li\u1ec7u, ph\u00e2n quy\u1ec1n b\u1ea3o m\u1eadt \u0111\u1ed9c l\u1eadp.\n\n---\n\n## 2. B\u00ed k\u00edp s\u1ed1ng c\u00f2n: C\u01a1 ch\u1ebf Token Sharing \u0110a Subdomain\n\n\u0110\u00e2y l\u00e0 l\u1ed7i kinh \u0111i\u1ec3n khi\u1ebfn 80% anh em m\u1edbi l\u00e0m vi\u1ec7c v\u1edbi EzyPlatform b\u1ecb \"v\u00f2 \u0111\u1ea7u b\u1ee9t tai\":\n\n> *\"T\u1ea1i sao m\u00ecnh \u0111\u0103ng nh\u1eadp v\u00e0o trang Admin th\u00ec m\u01b0\u1ee3t m\u00e0, nh\u01b0ng khi m\u1edf sang trang web xem tr\u01b0\u1edbc (Preview Iframe trong VS Code) th\u00ec l\u1ea1i b\u1ecb tr\u1eafng tinh ho\u1eb7c b\u1eaft \u0111\u0103ng nh\u1eadp l\u1ea1i li\u00ean t\u1ee5c?\"*\n\nNguy\u00ean nh\u00e2n n\u1eb1m \u1edf ch\u00ednh s\u00e1ch b\u1ea3o m\u1eadt **SameSite \/ Third-Party Cookies** c\u1ee7a c\u00e1c tr\u00ecnh duy\u1ec7t hi\u1ec7n \u0111\u1ea1i (Chrome 120+, Safari):\n\n![C\u01a1 ch\u1ebf Token Sharing \u0110a T\u00ean Mi\u1ec1n tr\u00ean EzyPlatform](https:\/\/images.viblo.asia\/46bdc677-4cf6-490e-b1ad-0ce1e6a7d64a.png)\n*So s\u00e1nh: Cookie Host-Only l\u00e0m v\u0103ng session khi chuy\u1ec3n trang, trong khi Token Sharing Domain chia s\u1ebb token m\u01b0\u1ee3t m\u00e0 gi\u1eefa m\u1ecdi subdomain.*\n\n* **N\u1ebfu kh\u00f4ng c\u1ea5u h\u00ecnh Token Sharing:** Cookie \u0111\u0103ng nh\u1eadp ch\u1ec9 c\u00f3 ph\u1ea1m vi \u1edf \u0111\u00fang host \u0111\u00f3 (`admin.lepetitbakery.vn`). Khi m\u1edf trang con \u1edf domain kh\u00e1c ho\u1eb7c iframe, tr\u00ecnh duy\u1ec7t t\u1eeb ch\u1ed1i g\u1eedi cookie \u2794 L\u1ed7i 401 Unauthorized ho\u1eb7c tr\u1eafng m\u00e0n h\u00ecnh.\n* **Gi\u1ea3i ph\u00e1p chu\u1ea9n m\u1ef1c c\u1ee7a EzyPlatform:** Khai b\u00e1o c\u1eb7p domain `lepetitbakery.vn:.lepetitbakery.vn` trong c\u1ea5u h\u00ecnh m\u00e1y ch\u1ee7. Cookie s\u1ebd \u0111\u01b0\u1ee3c g\u1eafn thu\u1ed9c t\u00ednh `Domain=.lepetitbakery.vn; SameSite=Lax; Secure`, cho ph\u00e9p to\u00e0n b\u1ed9 subdomain d\u00f9ng chung phi\u00ean l\u00e0m vi\u1ec7c an to\u00e0n 100%!\n\n---\n\n## 3. Th\u1ef1c chi\u1ebfn 4 b\u01b0\u1edbc: T\u1eeb t\u00ean mi\u1ec1n tr\u1ea7n \u0111\u1ebfn website kh\u00f3a xanh ho\u00e0n h\u1ea3o\n\nB\u00e2y gi\u1edd, h\u00e3y c\u00f9ng m\u00ecnh m\u1edf DNS Management v\u00e0 EzyPlatform Admin l\u00ean \u0111\u1ec3 c\u1ea5u h\u00ecnh nh\u00e9!\n\n### B\u01b0\u1edbc 1: C\u1ea5u h\u00ecnh b\u1ea3n ghi DNS tr\u1ecf v\u1ec1 IP VPS `157.66.47.xxx`\n\n\u0110\u0103ng nh\u1eadp v\u00e0o tr\u00ecnh qu\u1ea3n l\u00fd DNS c\u1ee7a b\u1ea1n (Cloudflare, Namecheap, PA Vietnam, v.v.) v\u00e0 th\u00eam 3 b\u1ea3n ghi c\u01a1 b\u1ea3n:\n\n![B\u1ea3ng c\u1ea5u h\u00ecnh b\u1ea3n ghi DNS tr\u1ecf v\u1ec1 VPS](https:\/\/images.viblo.asia\/12764207-9fc7-4869-b361-b3213ff29162.png)\n*C\u1ea5u h\u00ecnh b\u1ea3n ghi A v\u00e0 CNAME tr\u1ecf v\u1ec1 IP VPS 157.66.47.xxx v\u1edbi ch\u1ebf \u0111\u1ed9 DNS Only.*\n\n| Type | Name | Content (IPv4) | TTL | Proxy Status |\n| :--- | :--- | :--- | :--- | :--- |\n| **A** | `@` | `157.66.47.xxx` | Auto | DNS only |\n| **CNAME** | `www` | `lepetitbakery.vn` | Auto | DNS only |\n| **A** | `admin` | `157.66.47.xxx` | Auto | DNS only |\n\n> **(B\u00ed k\u00edp \ud83d\udca1):** Trong l\u1ea7n \u0111\u1ea7u c\u1ea5p ch\u1ee9ng ch\u1ec9 SSL qua EzyPlatform, h\u00e3y \u0111\u1ec3 ch\u1ebf \u0111\u1ed9 **DNS only** (\u0111\u00e1m m\u00e2y m\u00e0u x\u00e1m tr\u00ean Cloudflare) \u0111\u1ec3 Let's Encrypt x\u00e1c th\u1ef1c ch\u1ee9ng ch\u1ec9 tr\u1ef1c ti\u1ebfp v\u1edbi m\u00e1y ch\u1ee7 VPS m\u00e0 kh\u00f4ng b\u1ecb ch\u1eb7n b\u1edfi proxy trung gian.\n\n---\n\n### B\u01b0\u1edbc 2: K\u00edch ho\u1ea1t SSL Let's Encrypt 1-Click qua plugin EzySupport\n\nM\u1edf trang qu\u1ea3n tr\u1ecb EzyPlatform, v\u00e0o m\u1ee5c **EzySupport > SSL Manager**:\n\n![Giao di\u1ec7n k\u00edch ho\u1ea1t SSL Let's Encrypt tr\u00ean EzySupport](https:\/\/images.viblo.asia\/567ea616-169d-499e-830e-acfa79a68eb9.png)\n*Ch\u1ee9ng ch\u1ec9 SSL Let's Encrypt \u0111\u01b0\u1ee3c c\u1ea5p ph\u00e1t th\u00e0nh c\u00f4ng k\u00e8m t\u00ednh n\u0103ng t\u1ef1 \u0111\u1ed9ng gia h\u1ea1n 30 ng\u00e0y tr\u01b0\u1edbc khi h\u1ebft h\u1ea1n.*\n\nCh\u1ec9 c\u1ea7n nh\u1eadp t\u00ean mi\u1ec1n `lepetitbakery.vn, admin.lepetitbakery.vn` v\u00e0 b\u1ea5m n\u00fat **\"Issue Certificate\"**. H\u1ec7 th\u1ed1ng t\u1ef1 \u0111\u1ed9ng:\n1. Giao ti\u1ebfp v\u1edbi m\u00e1y ch\u1ee7 Let's Encrypt qua giao th\u1ee9c ACME.\n2. X\u00e1c th\u1ef1c quy\u1ec1n s\u1edf h\u1eefu t\u00ean mi\u1ec1n trong 10 gi\u00e2y.\n3. T\u1ef1 \u0111\u1ed9ng n\u1ea1p ch\u1ee9ng ch\u1ec9 SSL v\u00e0o Nginx v\u00e0 k\u00edch ho\u1ea1t HTTPS ngay l\u1eadp t\u1ee9c m\u00e0 kh\u00f4ng c\u1ea7n kh\u1edfi \u0111\u1ed9ng l\u1ea1i m\u00e1y ch\u1ee7!\n\n---\n\n### B\u01b0\u1edbc 3: C\u1ea5u h\u00ecnh Token Sharing & Allowed CORS trong `\/settings\/regular`\n\n\u0110\u1ec3 tr\u00e1nh l\u1ed7i v\u0103ng phi\u00ean l\u00e0m vi\u1ec7c v\u00e0 tr\u1eafng m\u00e0n h\u00ecnh Preview, h\u00e3y truy c\u1eadp v\u00e0o menu **Settings > Regular**:\n\n![C\u1ea5u h\u00ecnh Token Sharing Domains v\u00e0 Allowed CORS](https:\/\/images.viblo.asia\/29720ddd-3cb3-40a6-ab09-efcce9faea30.png)\n*Thi\u1ebft l\u1eadp Token Sharing Domains v\u00e0 danh s\u00e1ch CORS Allowed Origins chu\u1ea9n m\u1ef1c.*\n\n\u0110i\u1ec1n ch\u00ednh x\u00e1c c\u00e1c gi\u00e1 tr\u1ecb:\n* **Token Sharing Domains:**\n  ```text\n  lepetitbakery.vn:.lepetitbakery.vn, 1576647xxx-admin.interdata.io.vn:.interdata.io.vn\n  ```\n* **Allowed CORS Origins:**\n  ```text\n  https:\/\/lepetitbakery.vn, https:\/\/admin.lepetitbakery.vn\n  ```\n* **Allowed Upload MIME Types:** B\u1ed5 sung `image\/svg+xml, text\/css, application\/javascript, font\/woff2, image\/webp` \u0111\u1ec3 kh\u00f4ng b\u1ecb ch\u1eb7n upload \u1ea3nh b\u00e1nh ng\u1ecdt hay font ch\u1eef.\n\nB\u1ea5m **\"L\u01b0u Thi\u1ebft L\u1eadp\"**. To\u00e0n b\u1ed9 h\u1ec7 th\u1ed1ng gi\u1edd \u0111\u00e2y \u0111\u00e3 \u0111\u1ed3ng b\u1ed9 phi\u00ean l\u00e0m vi\u1ec7c xuy\u00ean su\u1ed1t gi\u1eefa c\u00e1c subdomain!\n\n---\n\n### B\u01b0\u1edbc 4: Ki\u1ec3m tra th\u00e0nh qu\u1ea3 tr\u1ef1c quan v\u1edbi \u1ed4 Kh\u00f3a Xanh HTTPS\n\nB\u00e2y gi\u1edd, h\u00e3y m\u1edf tab \u1ea9n danh tr\u00ean Chrome v\u00e0 truy c\u1eadp v\u00e0o `https:\/\/lepetitbakery.vn`:\n\n![Tr\u00ecnh duy\u1ec7t truy c\u1eadp t\u00ean mi\u1ec1n th\u1eadt v\u1edbi \u1ed5 kh\u00f3a xanh an to\u00e0n](https:\/\/images.viblo.asia\/eaa589d6-3553-4cc8-a623-1ee9111b785f.png)\n*Website hi\u1ec3n th\u1ecb \u1ed5 kh\u00f3a xanh b\u1ea3o m\u1eadt A+, t\u1ed1c \u0111\u1ed9 ph\u1ea3n h\u1ed3i TTFB ch\u1ec9 115ms v\u00e0 s\u1eb5n s\u00e0ng ph\u1ee5c v\u1ee5 kh\u00e1ch h\u00e0ng!*\n\n\u1ed4 kh\u00f3a xanh xu\u1ea5t hi\u1ec7n ki\u00eau h\u00e3nh tr\u00ean thanh \u0111\u1ecba ch\u1ec9. Ch\u1ee9ng ch\u1ec9 b\u1ea3o m\u1eadt c\u1ea5p b\u1edfi Let's Encrypt h\u1ee3p l\u1ec7, to\u00e0n b\u1ed9 lu\u1ed3ng thanh to\u00e1n v\u00e0 d\u1eef li\u1ec7u gi\u1ecf h\u00e0ng \u0111\u01b0\u1ee3c m\u00e3 h\u00f3a SSL 2048-bit an to\u00e0n tuy\u1ec7t \u0111\u1ed1i! \ud83c\udf89\n\n---\n\n## 4. 3 b\u1eaby l\u1ed7i kinh \u0111i\u1ec3n khi Go-Live & C\u00e1ch n\u00e9 \ud83d\ude21\n\nD\u00f9 quy tr\u00ecnh r\u1ea5t \u0111\u01a1n gi\u1ea3n, anh em dev v\u1eabn th\u01b0\u1eddng g\u1eb7p ph\u1ea3i 3 l\u1ed7i \"d\u1edf kh\u00f3c d\u1edf c\u01b0\u1eddi\" n\u00e0y:\n\n### B\u1eaby l\u1ed7i #1: L\u1ed7i \"Mixed Content\" khi\u1ebfn \u1ed5 kh\u00f3a xanh b\u1ecb v\u1ee1 \ud83d\ude23\n- **Hi\u1ec7n t\u01b0\u1ee3ng:** Truy c\u1eadp qua HTTPS nh\u01b0ng tr\u00ecnh duy\u1ec7t hi\u1ec7n tam gi\u00e1c v\u00e0ng c\u1ea3nh b\u00e1o: *\"Trang web n\u00e0y kh\u00f4ng an to\u00e0n ho\u00e0n to\u00e0n (Mixed Content)\"*.\n- **Nguy\u00ean nh\u00e2n:** Trong file `head.html` ho\u1eb7c `content.html`, b\u1ea1n nh\u00fang \u1ea3nh, font ho\u1eb7c file script b\u1eb1ng \u0111\u01b0\u1eddng d\u1eabn tuy\u1ec7t \u0111\u1ed1i b\u1eaft \u0111\u1ea7u b\u1eb1ng `http:\/\/` (v\u00ed d\u1ee5: `http:\/\/fonts.googleapis.com\/...` ho\u1eb7c `http:\/\/157.66.47.xxx\/media\/...`).\n- **C\u00e1ch n\u00e9 (Recommend \ud83d\udc4d):** Lu\u00f4n d\u00f9ng giao th\u1ee9c t\u01b0\u01a1ng \u0111\u1ed1i (`\/\/fonts.googleapis.com\/...`) ho\u1eb7c b\u1eaft \u0111\u1ea7u b\u1eb1ng `https:\/\/`. Trong EzyPlatform, lu\u00f4n d\u00f9ng c\u00e1c thu\u1ed9c t\u00ednh chu\u1ea9n `ezy:msrc` v\u00e0 `ezy:mhref` \u0111\u1ec3 h\u1ec7 th\u1ed1ng t\u1ef1 \u0111\u1ed9ng sinh link b\u1ea3o m\u1eadt.\n\n### B\u1eaby l\u1ed7i #2: V\u00f2ng l\u1eb7p chuy\u1ec3n h\u01b0\u1edbng v\u00f4 t\u1eadn (ERR_TOO_MANY_REDIRECTS) \ud83d\ude21\n- **Hi\u1ec7n t\u01b0\u1ee3ng:** V\u1eeba b\u1eadt \u0111\u00e1m m\u00e2y m\u00e0u cam (Proxy) tr\u00ean Cloudflare xong, web l\u1eadp t\u1ee9c s\u1eadp v\u1edbi l\u1ed7i: `ERR_TOO_MANY_REDIRECTS`.\n- **Nguy\u00ean nh\u00e2n:** Cloudflare \u0111ang \u0111\u1ec3 ch\u1ebf \u0111\u1ed9 SSL l\u00e0 **Flexible** (Cloudflare n\u1ed1i t\u1edbi VPS b\u1eb1ng HTTP port 80), trong khi Nginx tr\u00ean VPS l\u1ea1i \u00e9p chuy\u1ec3n h\u01b0\u1edbng `HTTP \u2794 HTTPS port 443`, t\u1ea1o th\u00e0nh m\u1ed9t v\u00f2ng l\u1eb7p v\u0129nh c\u1eedu.\n- **C\u00e1ch n\u00e9 (B\u00ed k\u00edp \ud83d\udca1):** Tr\u00ean Cloudflare, v\u00e0o m\u1ee5c **SSL\/TLS**, chuy\u1ec3n ch\u1ebf \u0111\u1ed9 m\u00e3 h\u00f3a sang **Full (Strict)**. L\u00fac n\u00e0y Cloudflare s\u1ebd k\u1ebft n\u1ed1i an to\u00e0n t\u1edbi ch\u1ee9ng ch\u1ec9 Let's Encrypt th\u1eadt tr\u00ean VPS c\u1ee7a b\u1ea1n.\n\n### B\u1eaby l\u1ed7i #3: Qu\u00ean d\u1ea5u ch\u1ea5m `.` ph\u00eda tr\u01b0\u1edbc trong Token Sharing Domain \u26a0\ufe0f\n- **Hi\u1ec7n t\u01b0\u1ee3ng:** \u0110i\u1ec1n `lepetitbakery.vn:lepetitbakery.vn` (thi\u1ebfu d\u1ea5u ch\u1ea5m tr\u01b0\u1edbc domain \u0111\u00edch). Khi v\u00e0o subdomain `admin.`, cookie kh\u00f4ng \u0111\u01b0\u1ee3c chia s\u1ebb v\u00e0 trang web ti\u1ebfp t\u1ee5c b\u1ecb tr\u1eafng.\n- **C\u00e1ch n\u00e9 (L\u01b0u \u00fd \u26a0\ufe0f):** C\u00fa ph\u00e1p chu\u1ea9n c\u1ee7a RFC 6265 Cookie Specification b\u1eaft bu\u1ed9c ph\u1ea3i c\u00f3 d\u1ea5u ch\u1ea5m ph\u00eda tr\u01b0\u1edbc domain bao qu\u00e1t: `domain.com:.domain.com`.\n\n---\n\n## 5. Checklist 10 \u0110i\u1ec3m V\u00e0ng Tr\u01b0\u1edbc Khi B\u00e0n Giao Web Cho Kh\u00e1ch \ud83d\udccb\n\nTr\u01b0\u1edbc khi ch\u00ednh th\u1ee9c g\u1eedi link website cho \u0111\u1ed1i t\u00e1c ho\u1eb7c ch\u1ea1y qu\u1ea3ng c\u00e1o b\u00e1n h\u00e0ng, h\u00e3y d\u00e0nh 5 ph\u00fat ki\u1ec3m tra l\u1ea1i b\u1ea3ng checklist sau:\n\n| STT | H\u1ea1ng m\u1ee5c ki\u1ec3m tra | Ti\u00eau chu\u1ea9n \u0111\u1ea1t | Tr\u1ea1ng th\u00e1i |\n| :---: | :--- | :--- | :---: |\n| 1 | **SSL HTTPS** | Kh\u00f3a xanh h\u1ee3p l\u1ec7, kh\u00f4ng c\u00f3 c\u1ea3nh b\u00e1o b\u1ea3o m\u1eadt | \u2714 \u0110\u1ea1t |\n| 2 | **Mixed Content** | Kh\u00f4ng ch\u1ee9a b\u1ea5t k\u1ef3 link t\u00e0i nguy\u00ean `http:\/\/` n\u00e0o | \u2714 \u0110\u1ea1t |\n| 3 | **Token Sharing** | Iframe Preview VS Code v\u00e0 Admin kh\u00f4ng b\u1ecb v\u0103ng session | \u2714 \u0110\u1ea1t |\n| 4 | **Favicon & Logo** | Hi\u1ec3n th\u1ecb s\u1eafc n\u00e9t tr\u00ean tab tr\u00ecnh duy\u1ec7t (PNG\/SVG) | \u2714 \u0110\u1ea1t |\n| 5 | **SEO Meta Tags** | C\u00f3 th\u1ebb `title`, `meta description` v\u00e0 `og:image` | \u2714 \u0110\u1ea1t |\n| 6 | **Mobile Responsive** | Menu, n\u00fat b\u1ea5m, gi\u1ecf h\u00e0ng kh\u00f4ng b\u1ecb tr\u00e0n ngang tr\u00ean \u0111i\u1ec7n tho\u1ea1i | \u2714 \u0110\u1ea1t |\n| 7 | **Dark Mode FOUC** | Chuy\u1ec3n ch\u1ebf \u0111\u1ed9 kh\u00f4ng b\u1ecb ch\u1edbp tr\u1eafng m\u00e0n h\u00ecnh | \u2714 \u0110\u1ea1t |\n| 8 | **Webhook Telegram** | B\u1ea5m \u0111\u1eb7t th\u1eed \u0111\u01a1n h\u00e0ng \u2794 Telegram n\u1ed5 tin nh\u1eafn sau < 2s | \u2714 \u0110\u1ea1t |\n| 9 | **Email Invoice** | Kh\u00e1ch nh\u1eadn \u0111\u01b0\u1ee3c email h\u00f3a \u0111\u01a1n \u0111\u1eb9p m\u1eaft, kh\u00f4ng v\u00e0o Spam | \u2714 \u0110\u1ea1t |\n| 10 | **T\u1ed1c \u0111\u1ed9 t\u1ea3i trang** | TTFB < 200ms tr\u00ean h\u1ea1 t\u1ea7ng VPS | \u2714 \u0110\u1ea1t |\n\n---\n\n## 6. T\u1ed5ng k\u1ebft & K\u1ef3 ti\u1ebfp theo\n\nVi\u1ec7c tr\u1ecf t\u00ean mi\u1ec1n th\u01b0\u01a1ng hi\u1ec7u ri\u00eang v\u00e0 k\u00edch ho\u1ea1t \u1ed5 kh\u00f3a xanh HTTPS l\u00e0 c\u1ed9t m\u1ed1c bi\u1ebfn s\u1ea3n ph\u1ea9m Vibe Coding c\u1ee7a b\u1ea1n t\u1eeb m\u1ed9t \"d\u1ef1 \u00e1n c\u00e1 nh\u00e2n th\u1eed nghi\u1ec7m\" th\u00e0nh m\u1ed9t **n\u1ec1n t\u1ea3ng kinh doanh s\u1eb5n s\u00e0ng t\u1ea1o ra doanh thu th\u1ef1c t\u1ebf**!\n\n### \ud83c\udfaf 3 b\u00e0i h\u1ecdc c\u1ed1t l\u00f5i t\u1eeb b\u00e0i vi\u1ebft n\u00e0y:\n1. **SSL 1-Click v\u1edbi EzySupport:** X\u00f3a b\u1ecf ho\u00e0n to\u00e0n n\u1ed7i s\u1ee3 g\u00f5 l\u1ec7nh certbot trong terminal.\n2. **Token Sharing Domain l\u00e0 b\u00ed quy\u1ebft s\u1ed1ng c\u00f2n:** C\u00fa ph\u00e1p `domain.com:.domain.com` gi\u00fap phi\u00ean l\u00e0m vi\u1ec7c v\u00e0 iframe preview m\u01b0\u1ee3t m\u00e0 100%.\n3. **Lu\u00f4n r\u00e0 so\u00e1t checklist 10 \u0111i\u1ec3m v\u00e0ng:** \u0110\u1ea3m b\u1ea3o kh\u00f4ng d\u00ednh b\u1eaby Mixed Content hay l\u1ed7i v\u00f2ng l\u1eb7p chuy\u1ec3n h\u01b0\u1edbng Cloudflare tr\u01b0\u1edbc khi Go-Live.\n\n\u1ede b\u00e0i vi\u1ebft ti\u1ebfp theo, ch\u00fang ta s\u1ebd m\u1edf r\u1ed9ng h\u1ec7 sinh th\u00e1i thanh to\u00e1n v\u00e0 ng\u01b0\u1eddi d\u00f9ng l\u00ean t\u1ea7m cao m\u1edbi:\n\n\ud83d\udc49 **[Vibe Coding Th\u1ef1c Chi\u1ebfn #12] M\u1edf R\u1ed9ng H\u1ec7 Sinh Th\u00e1i: T\u00edch H\u1ee3p C\u1ed5ng Thanh To\u00e1n VietQR \/ VNPay Sandbox & \u0110\u0103ng Nh\u1eadp 1 Ch\u1ea1m Google OAuth!**\n\nCh\u00fang ta s\u1ebd cho AI k\u1ebft n\u1ed1i t\u00ednh n\u0103ng t\u1ea1o m\u00e3 VietQR \u0111\u1ed9ng theo t\u1eebng \u0111\u01a1n h\u00e0ng (kh\u00e1ch qu\u00e9t m\u00e3 chuy\u1ec3n kho\u1ea3n l\u00e0 \u0111\u01a1n t\u1ef1 \u0111\u1ed5i sang \"\u0110\u00c3 THANH TO\u00c1N\") v\u00e0 k\u00edch ho\u1ea1t t\u00ednh n\u0103ng \u0111\u0103ng nh\u1eadp 1 ch\u1ea1m qua Google ch\u1ec9 trong v\u00e0i d\u00f2ng c\u1ea5u h\u00ecnh!\n\n---\n\n> \ud83d\udcac **G\u00f3c th\u1ea3o lu\u1eadn:** Anh em th\u00edch qu\u1ea3n l\u00fd DNS tr\u1ef1c ti\u1ebfp tr\u00ean nh\u00e0 cung c\u1ea5p t\u00ean mi\u1ec1n hay qua Cloudflare? \u0110\u00e3 bao gi\u1edd anh em b\u1ecb \"v\u1eadt\" b\u1edfi l\u1ed7i tr\u1eafng m\u00e0n h\u00ecnh iframe do cookie SameSite ch\u01b0a? H\u00e3y c\u00f9ng chia s\u1ebb kinh nghi\u1ec7m b\u00ean d\u01b0\u1edbi nh\u00e9!  \n>  \n> N\u1ebfu th\u1ea5y b\u00e0i vi\u1ebft n\u00e0y h\u1eefu \u00edch, \u0111\u1eebng qu\u00ean b\u1ea5m **Upvote \ud83d\udc4d** v\u00e0 **Bookmark (Clip) \ud83d\udd16** \u0111\u1ec3 \u0111\u00f3n \u0111\u1ecdc ti\u1ebfp B\u00e0i #12 nh\u00e9. Ch\u00fac anh em Vibe Coding th\u1eadt th\u0103ng hoa!","published_at":"2026-10-25T17:12:59.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T17:13:07.000000Z","edited_at":"2026-10-18T17:30:20.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":12,"points":0,"views_count":0,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/dd7256e6-8676-4ac2-9d91-782736d50edd.png","user":{"data":{"id":212424,"url":"https:\/\/viblo.asia\/u\/arya.it","avatar":"5f571f56-1f15-4d86-abea-d37a3ae5bcd5.png","name":"Duong Nguyen","username":"arya.it","followers_count":0,"reputation":24,"posts_count":9,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"dns","name":"dns"},{"slug":"ssl","name":"SSL"},{"slug":"web-development","name":"Web Development"}]},"commentators":{"data":[]}},{"id":109674,"title":"Trang Chu\u0309 iwinclub","slug":"1XVOW0e1VMz","url":"https:\/\/viblo.asia\/p\/trang-chu-iwinclub-1XVOW0e1VMz","user_id":227020,"moderation":"discarded","transliterated":"trang-chu-iwinclub","contents_short":"IWINCLUB mang \u0111\u1ebfn tr\u1ea3i nghi\u1ec7m gi\u1ea3i tr\u00ed tr\u1ef1c tuy\u1ebfn v\u1edbi giao di\u1ec7n hi\u1ec7n \u0111\u1ea1i, danh m\u1ee5c tr\u00f2 ch\u01a1i \u0111a d\u1ea1ng v\u00e0 c\u00e1ch s\u1eed d\u1ee5ng thu\u1eadn ti\u1ec7n. N\u1ec1n t\u1ea3ng ch\u00fa tr\u1ecdng c\u1ea3i thi\u1ec7n ch\u1ea5t l\u01b0\u1ee3ng d\u1ecbch v\u1ee5, t\u1ed1i \u01b0u tr\u1ea3i nghi\u1ec7m ng\u01b0\u1eddi d\u00f9ng v\u00e0 c\u1eadp nh\u1eadt nhi\u1ec1u ch\u01b0\u01a1ng tr\u00ecnh \u01b0u \u0111\u00e3i, gi\u00fap ng\u01b0\u1eddi ch\u01a1i d\u1ec5 d\u00e0ng kh\u00e1m ph\u00e1 c\u00e1c l\u1ef1a ch\u1ecdn gi\u1ea3i tr\u00ed trong n\u0103m 2026.\nWebsite: https:\/\/iwinclubz.eu.com\/\nHotline: 0939 555 610\nEmail: iwinclubz.eu.com...","contents":"IWINCLUB mang \u0111\u1ebfn tr\u1ea3i nghi\u1ec7m gi\u1ea3i tr\u00ed tr\u1ef1c tuy\u1ebfn v\u1edbi giao di\u1ec7n hi\u1ec7n \u0111\u1ea1i, danh m\u1ee5c tr\u00f2 ch\u01a1i \u0111a d\u1ea1ng v\u00e0 c\u00e1ch s\u1eed d\u1ee5ng thu\u1eadn ti\u1ec7n. N\u1ec1n t\u1ea3ng ch\u00fa tr\u1ecdng c\u1ea3i thi\u1ec7n ch\u1ea5t l\u01b0\u1ee3ng d\u1ecbch v\u1ee5, t\u1ed1i \u01b0u tr\u1ea3i nghi\u1ec7m ng\u01b0\u1eddi d\u00f9ng v\u00e0 c\u1eadp nh\u1eadt nhi\u1ec1u ch\u01b0\u01a1ng tr\u00ecnh \u01b0u \u0111\u00e3i, gi\u00fap ng\u01b0\u1eddi ch\u01a1i d\u1ec5 d\u00e0ng kh\u00e1m ph\u00e1 c\u00e1c l\u1ef1a ch\u1ecdn gi\u1ea3i tr\u00ed trong n\u0103m 2026. \nWebsite: https:\/\/iwinclubz.eu.com\/  \nHotline: 0939 555 610 \nEmail: iwinclubz.eu.com@gmail.com \nAndress: 311 B\u00ecnh Long, B\u00ecnh H\u01b0ng H\u00f2a, H\u1ed3 Ch\u00ed Minh, Vi\u1ec7t Nam \nHastag: #IWINCLUB #IWINCLUB2026 #IWINCLUBChinhThuc #GiaiTriDinhCao #KhamPhaIWINCLUB  \nhttps:\/\/x.com\/iwinclubzeucom  \nhttps:\/\/www.pinterest.com\/iwinclubzeucom\/  \nhttps:\/\/www.youtube.com\/@iwinclubzeucom  \nhttps:\/\/github.com\/iwinclubzeucom  \nhttps:\/\/www.twitch.tv\/iwinclubzeucom  \nhttps:\/\/hub.docker.com\/u\/iwinclubzeucom  \nhttps:\/\/500px.com\/p\/iwinclubzeucom  \nhttps:\/\/www.instapaper.com\/p\/iwinclubzeucom  \nhttps:\/\/profile.hatena.ne.jp\/iwinclubzeucom\/profile  \nhttps:\/\/telegra.ph\/Trang-Chu-iwinclub-10-24","published_at":"2026-10-25T13:45:37.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T13:46:02.000000Z","edited_at":"2026-10-25T13:45:33.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":0,"points":0,"views_count":1,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/1fef01af-b310-4282-afb2-6d9d72ce784e.png","user":{"data":{"id":227020,"url":"https:\/\/viblo.asia\/u\/iwinclubzeucom","avatar":"c05dc4f7-613c-4469-aa62-9a1b95a9ff1c.jpg","name":"iwinclubzeucom","username":"iwinclubzeucom","followers_count":0,"reputation":0,"posts_count":0,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"2d-game-artist","name":"2d game artist"}]},"commentators":{"data":[]}},{"id":107329,"title":"Series Java Swing B\u00e0i 8: GridLayout: Hi\u1ec3n th\u1ecb c\u00e1c th\u00e0nh ph\u1ea7n theo d\u1ea1ng l\u01b0\u1edbi (Grid)","slug":"R5JRQlKr4Gv","url":"https:\/\/viblo.asia\/p\/series-java-swing-bai-8-gridlayout-hien-thi-cac-thanh-phan-theo-dang-luoi-grid-R5JRQlKr4Gv","user_id":182653,"moderation":null,"transliterated":"series-java-swing-bai-8-gridlayout-hien-thi-cac-thanh-phan-theo-dang-luoi-grid","contents_short":"N\u1ebfu BorderLayout chia kh\u00f4ng gian th\u00e0nh 5 v\u00f9ng \u0111\u1eb7c th\u00f9, th\u00ec GridLayout chia kh\u00f4ng gian l\u00e0m vi\u1ec7c th\u00e0nh m\u1ed9t b\u1ea3ng l\u01b0\u1edbi (grid) g\u1ed3m c\u00e1c h\u00e0ng v\u00e0 c\u1ed9t.\n\nH\u00ecnh \u1ea3nh d\u1ec5 h\u00ecnh dung nh\u1ea5t c\u1ee7a GridLayout ch\u00ednh l\u00e0 b\u00e0n ph\u00edm s\u1ed1 c\u1ee7a m\u00e1y t\u00ednh b\u1ecf t\u00fai (Calculator) ho\u1eb7c m\u1ed9t b\u00e0n c\u1edd vua: m\u1ecdi \u00f4 vu\u00f4ng \u0111\u1ec1u \u0111\u01b0\u1ee3c chia \u0111\u1ec1u t\u0103m t\u1eafp.\n\n1. Ba \u0111\u1eb7c \u0111i\u1ec3m \"c\u1ee9ng nh\u1eafc\" c\u1ee7a GridLayout\n\n1.  B\u00ecnh \u0111\u1eb3ng tuy\u1ec7t \u0111\u1ed1i v\u1ec1 k\u00edch th\u01b0\u1edbc: D\u00f9 trong \u00f4 ch\u1ee9...","contents":"N\u1ebfu `BorderLayout` chia kh\u00f4ng gian th\u00e0nh 5 v\u00f9ng \u0111\u1eb7c th\u00f9, th\u00ec `GridLayout` chia kh\u00f4ng gian l\u00e0m vi\u1ec7c th\u00e0nh m\u1ed9t **b\u1ea3ng l\u01b0\u1edbi (grid)** g\u1ed3m c\u00e1c h\u00e0ng v\u00e0 c\u1ed9t.\n\nH\u00ecnh \u1ea3nh d\u1ec5 h\u00ecnh dung nh\u1ea5t c\u1ee7a `GridLayout` ch\u00ednh l\u00e0 **b\u00e0n ph\u00edm s\u1ed1 c\u1ee7a m\u00e1y t\u00ednh b\u1ecf t\u00fai (Calculator)** ho\u1eb7c m\u1ed9t b\u00e0n c\u1edd vua: m\u1ecdi \u00f4 vu\u00f4ng \u0111\u1ec1u \u0111\u01b0\u1ee3c chia \u0111\u1ec1u t\u0103m t\u1eafp.\n\n## 1. Ba \u0111\u1eb7c \u0111i\u1ec3m \"c\u1ee9ng nh\u1eafc\" c\u1ee7a GridLayout\n\n1.  **B\u00ecnh \u0111\u1eb3ng tuy\u1ec7t \u0111\u1ed1i v\u1ec1 k\u00edch th\u01b0\u1edbc:** D\u00f9 trong \u00f4 ch\u1ee9a m\u1ed9t n\u00fat b\u1ea5m c\u00f3 ch\u1eef r\u1ea5t d\u00e0i hay m\u1ed9t n\u00fat b\u1ea5m ch\u1ec9 c\u00f3 1 k\u00fd t\u1ef1, `GridLayout` s\u1ebd **\u00e9p** t\u1ea5t c\u1ea3 c\u00e1c \u00f4 ph\u1ea3i c\u00f3 k\u00edch th\u01b0\u1edbc r\u1ed9ng v\u00e0 cao b\u1eb1ng h\u1ec7t nhau. K\u00edch th\u01b0\u1edbc c\u1ee7a m\u1ed7i \u00f4 = (T\u1ed5ng k\u00edch th\u01b0\u1edbc c\u1eeda s\u1ed5) \/ (S\u1ed1 h\u00e0ng x S\u1ed1 c\u1ed9t).\n    \n2.  **V\u00f4 hi\u1ec7u h\u00f3a preferredSize:** C\u00e1c l\u1ec7nh nh\u01b0 `setPreferredSize()`, `setMinimumSize()` hay `setMaximumSize()` ho\u00e0n to\u00e0n v\u00f4 t\u00e1c d\u1ee5ng trong Layout n\u00e0y.\n    \n3.  **Th\u1ee9 t\u1ef1 l\u1ea5p \u0111\u1ea7y:** Khi b\u1ea1n g\u1ecdi l\u1ec7nh `add(Component)`, c\u00e1c th\u00e0nh ph\u1ea7n s\u1ebd t\u1ef1 \u0111\u1ed9ng l\u1ea5p \u0111\u1ea7y v\u00e0o l\u01b0\u1edbi theo th\u1ee9 t\u1ef1: **T\u1eeb tr\u00e1i sang ph\u1ea3i, h\u1ebft h\u00e0ng tr\u00ean s\u1ebd t\u1ef1 \u0111\u1ed9ng r\u1edbt xu\u1ed1ng h\u00e0ng d\u01b0\u1edbi**. B\u1ea1n kh\u00f4ng th\u1ec3 ch\u1ec9 \u0111\u1ecbnh \u0111\u00edch danh \"h\u00e3y \u0111\u1eb7t n\u00fat n\u00e0y v\u00e0o t\u1ecda \u0111\u1ed9 h\u00e0ng 2 c\u1ed9t 3\".\n    \n\n## 2. C\u00e1c h\u00e0m kh\u1edfi t\u1ea1o (Constructors)\n\nB\u1ea1n c\u1ea7n x\u00e1c \u0111\u1ecbnh tr\u01b0\u1edbc s\u1ed1 h\u00e0ng (rows) v\u00e0 s\u1ed1 c\u1ed9t (columns) khi kh\u1edfi t\u1ea1o Layout.\n\n-   **`GridLayout(int rows, int cols)`**: Kh\u1edfi t\u1ea1o l\u01b0\u1edbi kh\u00f4ng c\u00f3 kho\u1ea3ng tr\u1ed1ng gi\u1eefa c\u00e1c \u00f4.\n    \n-   **`GridLayout(int rows, int cols, int hgap, int vgap)`**: Kh\u1edfi t\u1ea1o l\u01b0\u1edbi c\u00f3 kho\u1ea3ng tr\u1ed1ng theo chi\u1ec1u ngang (`hgap`) v\u00e0 chi\u1ec1u d\u1ecdc (`vgap`).\n    \n\n**Quy t\u1eafc \u0111\u1eb7c bi\u1ec7t (M\u1eb9o n\u00e2ng cao):** B\u1ea1n kh\u00f4ng \u0111\u01b0\u1ee3c ph\u00e9p thi\u1ebft l\u1eadp c\u1ea3 s\u1ed1 h\u00e0ng v\u00e0 s\u1ed1 c\u1ed9t \u0111\u1ec1u b\u1eb1ng 0 (s\u1ebd b\u00e1o l\u1ed7i). Tuy nhi\u00ean, b\u1ea1n c\u00f3 th\u1ec3 thi\u1ebft l\u1eadp **m\u1ed9t trong hai gi\u00e1 tr\u1ecb b\u1eb1ng 0**.\n\n-   `new GridLayout(0, 3)`: S\u1ed1 c\u1ed9t c\u1ed1 \u0111\u1ecbnh l\u00e0 3, s\u1ed1 h\u00e0ng s\u1ebd t\u1ef1 \u0111\u1ed9ng sinh ra (dynamic) t\u00f9y thu\u1ed9c v\u00e0o vi\u1ec7c b\u1ea1n `add()` bao nhi\u00eau Component v\u00e0o l\u01b0\u1edbi.\n    \n-   `new GridLayout(4, 0)`: S\u1ed1 h\u00e0ng c\u1ed1 \u0111\u1ecbnh l\u00e0 4, s\u1ed1 c\u1ed9t s\u1ebd t\u1ef1 \u0111\u1ed9ng ph\u00ecnh ra.\n    \n\n## 3. Source code minh h\u1ecda: Giao di\u1ec7n M\u00e1y t\u00ednh b\u1ecf t\u00fai\n\n\u1ee8ng d\u1ee5ng kinh \u0111i\u1ec3n nh\u1ea5t c\u1ee7a `GridLayout` l\u00e0 t\u1ea1o b\u00e0n ph\u00edm. \u0110o\u1ea1n code sau s\u1ebd t\u1ea1o ra m\u1ed9t b\u1ed9 khung ph\u00edm b\u1ea5m m\u00e1y t\u00ednh c\u01a1 b\u1ea3n g\u1ed3m 4 h\u00e0ng v\u00e0 4 c\u1ed9t.\n\nJava\n\n```\nimport javax.swing.*;\nimport java.awt.*;\n\npublic class GridLayoutDemo extends JFrame {\n\n    public GridLayoutDemo() {\n        setTitle(\"M\u00e1y t\u00ednh b\u1ecf t\u00fai - GridLayout\");\n        setSize(300, 400);\n        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n        setLocationRelativeTo(null);\n        \n        \/\/ K\u1ebft h\u1ee3p BorderLayout \u1edf c\u1eeda s\u1ed5 ch\u00ednh\n        setLayout(new BorderLayout());\n\n        \/\/ 1. Ph\u1ea7n hi\u1ec3n th\u1ecb k\u1ebft qu\u1ea3 (D\u00f9ng v\u00f9ng NORTH)\n        JTextField txtDisplay = new JTextField(\"0\");\n        txtDisplay.setFont(new Font(\"Arial\", Font.BOLD, 30));\n        txtDisplay.setHorizontalAlignment(JTextField.RIGHT); \/\/ C\u0103n l\u1ec1 ph\u1ea3i\n        txtDisplay.setEditable(false);\n        txtDisplay.setPreferredSize(new Dimension(300, 60)); \/\/ T\u0103ng chi\u1ec1u cao c\u1ee7a \u00f4 nh\u1eadp\n        add(txtDisplay, BorderLayout.NORTH);\n\n        \/\/ 2. Ph\u1ea7n b\u00e0n ph\u00edm s\u1ed1 (D\u00f9ng JPanel + GridLayout ch\u1ee9a \u1edf v\u00f9ng CENTER)\n        JPanel keypadPanel = new JPanel();\n        \/\/ L\u01b0\u1edbi 4 h\u00e0ng, 4 c\u1ed9t, kho\u1ea3ng c\u00e1ch ngang d\u1ecdc l\u00e0 5px\n        keypadPanel.setLayout(new GridLayout(4, 4, 5, 5));\n        \n        \/\/ M\u1ea3ng ch\u1ee9a nh\u00e3n c\u1ee7a c\u00e1c n\u00fat b\u1ea5m theo \u0111\u00fang th\u1ee9 t\u1ef1 t\u1eeb tr\u00e1i qua ph\u1ea3i, tr\u00ean xu\u1ed1ng d\u01b0\u1edbi\n        String[] buttons = {\n            \"7\", \"8\", \"9\", \"\/\",\n            \"4\", \"5\", \"6\", \"*\",\n            \"1\", \"2\", \"3\", \"-\",\n            \"C\", \"0\", \"=\", \"+\"\n        };\n\n        \/\/ D\u00f9ng v\u00f2ng l\u1eb7p \u0111\u1ec3 t\u1ea1o v\u00e0 add c\u00e1c n\u00fat v\u00e0o Panel\n        for (String text : buttons) {\n            JButton btn = new JButton(text);\n            btn.setFont(new Font(\"Arial\", Font.BOLD, 20));\n            keypadPanel.add(btn);\n        }\n\n        \/\/ Add c\u1ee5m b\u00e0n ph\u00edm v\u00e0o gi\u1eefa c\u1eeda s\u1ed5\n        add(keypadPanel, BorderLayout.CENTER);\n    }\n\n    public static void main(String[] args) {\n        SwingUtilities.invokeLater(() -> {\n            new GridLayoutDemo().setVisible(true);\n        });\n    }\n}\n\n```\n\n## 4. T\u1ed5ng k\u1ebft: Khi n\u00e0o n\u00ean d\u00f9ng?\n\n**N\u00ean d\u00f9ng:**\n\n-   Thi\u1ebft k\u1ebf b\u00e0n ph\u00edm s\u1ed1 (Numpad, M\u00e1y t\u00ednh, POS t\u00ednh ti\u1ec1n).\n    \n-   B\u00e0n c\u1edd, ma tr\u1eadn game (C\u1edd vua, D\u00f2 m\u00ecn - Minesweeper, Tic-Tac-Toe).\n    \n-   Hi\u1ec3n th\u1ecb danh s\u00e1ch h\u00ecnh \u1ea3nh\/s\u1ea3n ph\u1ea9m c\u00f3 k\u00edch th\u01b0\u1edbc thumbnail b\u1eb1ng nhau (nh\u01b0 Gallery).\n    \n\n**Kh\u00f4ng n\u00ean d\u00f9ng:**\n\n-   Thi\u1ebft k\u1ebf Form nh\u1eadp li\u1ec7u. Do \u0111\u1eb7c t\u00ednh \u00e9p c\u00e1c \u00f4 b\u1eb1ng nhau, n\u1ebfu b\u1ea1n d\u00f9ng n\u00f3 cho Form, c\u1ed9t ch\u1ee9a nh\u00e3n (`JLabel`) s\u1ebd b\u1ecb k\u00e9o r\u1ed9ng ra b\u1eb1ng \u0111\u00fang c\u1ed9t ch\u1ee9a \u00f4 nh\u1eadp (`JTextField`), t\u1ea1o ra c\u00e1c kho\u1ea3ng tr\u1eafng kh\u1ed5ng l\u1ed3 r\u1ea5t thi\u1ebfu th\u1ea9m m\u1ef9. \u0110\u1ec3 thi\u1ebft k\u1ebf Form, ch\u00fang ta s\u1ebd c\u1ea7n \u0111\u1ebfn `GridBagLayout` (B\u00e0i 10).","published_at":"2026-10-25T12:21:03.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T15:56:02.000000Z","edited_at":"2026-09-26T01:39:19.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":3,"points":0,"views_count":11,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/99945cd4-db9c-4159-8254-020b4f9fb1dd.png","user":{"data":{"id":182653,"url":"https:\/\/viblo.asia\/u\/hhoang","avatar":"8392e404-ea43-497f-8b18-3777e24dc6ab.jpg","name":"Huy Ho\u00e0ng","username":"hhoang","followers_count":202,"reputation":14064,"posts_count":1576,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"backend","name":"Backend"}]},"commentators":{"data":[]}},{"id":109672,"title":"C\u00f3 t\u1eaft \u0111\u01b0\u1ee3c Reels tr\u00ean Facebook kh\u00f4ng? Nh\u1eefng g\u00ec l\u00e0m \u0111\u01b0\u1ee3c tr\u00ean iPhone v\u00e0 gi\u1edbi h\u1ea1n c\u1ee7a t\u1eebng c\u00e1ch (2026)","slug":"37LdeRyMVov","url":"https:\/\/viblo.asia\/p\/co-tat-duoc-reels-tren-facebook-khong-nhung-gi-lam-duoc-tren-iphone-va-gioi-han-cua-tung-cach-2026-37LdeRyMVov","user_id":226329,"moderation":null,"transliterated":"co-tat-duoc-reels-tren-facebook-khong-nhung-gi-lam-duoc-tren-iphone-va-gioi-han-cua-tung-cach-2026","contents_short":"M\u00ecnh m\u1edf Facebook \u0111\u1ec3 xem nh\u00f3m l\u1edbp c\u00f3 th\u00f4ng b\u00e1o g\u00ec, r\u1ed3i l\u01b0\u1edbt xu\u1ed1ng m\u1ed9t ch\u00fat l\u00e0 g\u1eb7p th\u01b0\u1edbc phim. Xem m\u1ed9t c\u00e1i, vu\u1ed1t l\u00ean c\u00e1i n\u1eefa, v\u1eady l\u00e0 m\u1ea5t n\u1eeda ti\u1ebfng. M\u00ecnh \u0111\u00e3 th\u1eed t\u00ecm m\u1ed9t c\u00e0i \u0111\u1eb7t ki\u1ec3u \"T\u1eaft Reels\" trong Facebook, v\u00e0 \u0111\u00e2y l\u00e0 nh\u1eefng g\u00ec m\u00ecnh t\u00ecm \u0111\u01b0\u1ee3c.\n\nB\u00e0i n\u00e0y d\u1ef1a tr\u00ean trang tr\u1ee3 gi\u00fap c\u1ee7a Facebook, m\u00ecnh ki\u1ec3m tra l\u1ea1i v\u00e0o ng\u00e0y 25\/10\/2026, tr\u00ean iPhone. T\u00ean menu n\u00e0o m\u00ecnh ch\u01b0a \u0111\u1ed1i chi\u1ebfu \u0111\u01b0\u1ee3c v\u1edbi b\u1ea3n ti\u1ebfng Vi\u1ec7t ...","contents":"M\u00ecnh m\u1edf Facebook \u0111\u1ec3 xem nh\u00f3m l\u1edbp c\u00f3 th\u00f4ng b\u00e1o g\u00ec, r\u1ed3i l\u01b0\u1edbt xu\u1ed1ng m\u1ed9t ch\u00fat l\u00e0 g\u1eb7p th\u01b0\u1edbc phim. Xem m\u1ed9t c\u00e1i, vu\u1ed1t l\u00ean c\u00e1i n\u1eefa, v\u1eady l\u00e0 m\u1ea5t n\u1eeda ti\u1ebfng. M\u00ecnh \u0111\u00e3 th\u1eed t\u00ecm m\u1ed9t c\u00e0i \u0111\u1eb7t ki\u1ec3u \"T\u1eaft Reels\" trong Facebook, v\u00e0 \u0111\u00e2y l\u00e0 nh\u1eefng g\u00ec m\u00ecnh t\u00ecm \u0111\u01b0\u1ee3c.\n\nB\u00e0i n\u00e0y d\u1ef1a tr\u00ean trang tr\u1ee3 gi\u00fap c\u1ee7a Facebook, m\u00ecnh ki\u1ec3m tra l\u1ea1i v\u00e0o ng\u00e0y 25\/10\/2026, tr\u00ean iPhone. T\u00ean menu n\u00e0o m\u00ecnh ch\u01b0a \u0111\u1ed1i chi\u1ebfu \u0111\u01b0\u1ee3c v\u1edbi b\u1ea3n ti\u1ebfng Vi\u1ec7t th\u00ec c\u00f3 k\u00e8m t\u00ean ti\u1ebfng Anh trong ngo\u1eb7c. T\u00ean menu c\u00f3 th\u1ec3 \u0111\u1ed5i khi \u1ee9ng d\u1ee5ng c\u1eadp nh\u1eadt.\n\n## Tr\u1ea3 l\u1eddi ng\u1eafn: kh\u00f4ng c\u00f3 n\u00fat t\u1eaft\n\nTrong tr\u1ee3 gi\u00fap c\u1ee7a Facebook, m\u00ecnh kh\u00f4ng t\u00ecm th\u1ea5y c\u00e0i \u0111\u1eb7t n\u00e0o \u0111\u1ec3 t\u1eaft Reels hay t\u1eaft b\u1ea3ng feed video. Ng\u01b0\u1ee3c l\u1ea1i, Facebook n\u00f3i r\u1eb1ng t\u1eeb th\u00e1ng 9 n\u0103m 2025, m\u1ecdi video tr\u00ean Facebook \u0111\u1ec1u l\u00e0 th\u01b0\u1edbc phim, b\u1ea5t k\u1ec3 d\u00e0i hay ng\u1eafn, quay d\u1ecdc hay quay ngang. Th\u01b0\u1edbc phim \u0111\u01b0\u1ee3c \u0111\u1ec1 xu\u1ea5t d\u1ef1a tr\u00ean nh\u1eefng g\u00ec Facebook cho l\u00e0 li\u00ean quan \u0111\u1ebfn b\u1ea1n, v\u00e0 c\u00f3 th\u1ec3 xu\u1ea5t hi\u1ec7n \u1edf B\u1ea3ng feed v\u00e0 \u1edf m\u1ee5c Video.\n\nC\u00e1c trang tr\u1ee3 gi\u00fap ch\u1ec9 h\u01b0\u1edbng d\u1eabn c\u00e1ch **g\u1eedi ph\u1ea3n h\u1ed3i** v\u1ec1 th\u01b0\u1edbc phim, kh\u00f4ng h\u01b0\u1edbng d\u1eabn c\u00e1ch x\u00f3a ch\u00fang. N\u00ean nh\u1eefng g\u00ec l\u00e0m \u0111\u01b0\u1ee3c b\u00ean d\u01b0\u1edbi \u0111\u1ec1u l\u00e0 \"th\u1ea5y \u00edt h\u01a1n\", kh\u00f4ng ph\u1ea3i \"kh\u00f4ng th\u1ea5y n\u1eefa\".\n\n## 1. Kh\u00f4ng quan t\u00e2m v\u00e0 \u1ea8n th\u01b0\u1edbc phim\n\nKhi \u0111ang xem m\u1ed9t th\u01b0\u1edbc phim:\n\n1. Ch\u1ea1m v\u00e0o **Xem th\u00eam** (More).\n2. Ch\u1ecdn **Kh\u00f4ng quan t\u00e2m** (Not Interested) \u0111\u1ec3 th\u1ea5y \u00edt th\u01b0\u1edbc phim t\u01b0\u01a1ng t\u1ef1 h\u01a1n, ho\u1eb7c **\u1ea8n th\u01b0\u1edbc phim** (Hide reel) \u0111\u1ec3 g\u1ee1 th\u01b0\u1edbc phim \u0111\u00f3.\n\nFacebook n\u00f3i \u1ea8n th\u01b0\u1edbc phim g\u1ee1 th\u01b0\u1edbc phim \u0111\u00f3 ngay v\u00e0 gi\u1ea3m n\u1ed9i dung t\u1eeb ng\u01b0\u1eddi s\u00e1ng t\u1ea1o \u0111\u00f3. Nh\u01b0ng t\u00e1c d\u1ee5ng l\u00ean c\u00e1c th\u01b0\u1edbc phim sau n\u00e0y \u0111\u1ebfn t\u1eeb t\u1eeb, v\u00e0 phai d\u1ea7n theo th\u1eddi gian. B\u1ea1n c\u0169ng kh\u00f4ng ho\u00e0n t\u00e1c tr\u1ef1c ti\u1ebfp \u0111\u01b0\u1ee3c; Facebook g\u1ee3i \u00fd \u0111\u00e1nh d\u1ea5u c\u00e1c th\u01b0\u1edbc phim t\u01b0\u01a1ng t\u1ef1 l\u00e0 **Quan t\u00e2m** (Interested) n\u1ebfu mu\u1ed1n \u0111\u1ea3o l\u1ea1i.\n\nGi\u1edbi h\u1ea1n: l\u00e0m t\u1eebng c\u00e1i m\u1ed9t. N\u1ebfu b\u1ea1n b\u1ea5m Kh\u00f4ng quan t\u00e2m 20 l\u1ea7n trong m\u1ed9t bu\u1ed5i t\u1ed1i th\u00ec c\u0169ng l\u00e0 20 l\u1ea7n \u0111\u00e3 m\u1edf Reels.\n\n## 2. D\u1ecdn B\u1ea3ng feed\n\nV\u1edbi b\u00e0i vi\u1ebft trong B\u1ea3ng feed, ch\u1ea1m v\u00e0o **T\u00f9y ch\u1ecdn** (Options) tr\u00ean b\u00e0i r\u1ed3i ch\u1ecdn:\n\n- **Kh\u00f4ng quan t\u00e2m** (Not Interested): \u00edt b\u00e0i ki\u1ec3u \u0111\u00f3 h\u01a1n.\n- **B\u1ecf theo d\u00f5i** (Unfollow): kh\u00f4ng th\u1ea5y b\u00e0i t\u1eeb ng\u01b0\u1eddi, Trang ho\u1eb7c nh\u00f3m \u0111\u00f3 n\u1eefa, nh\u01b0ng v\u1eabn l\u00e0 b\u1ea1n b\u00e8 ho\u1eb7c v\u1eabn \u1edf trong nh\u00f3m.\n\nB\u1ecf theo d\u00f5i kh\u00e1 h\u1eefu \u00edch v\u1edbi c\u00e1c Trang gi\u1ea3i tr\u00ed \u0111\u0103ng video li\u00ean t\u1ee5c. Mu\u1ed1n xem Facebook c\u00e1 nh\u00e2n h\u00f3a B\u1ea3ng feed th\u1ebf n\u00e0o th\u00ec v\u00e0o **C\u00e0i \u0111\u1eb7t & quy\u1ec1n ri\u00eang t\u01b0** (Settings & Privacy) \u203a **C\u00e0i \u0111\u1eb7t** (Settings) \u203a **T\u00f9y ch\u1ecdn n\u1ed9i dung** (Content preferences).\n\n## 3. Kh\u00f4ng cho video t\u1ef1 ph\u00e1t\n\nC\u00e1i n\u00e0y kh\u00f4ng x\u00f3a th\u01b0\u1edbc phim, nh\u01b0ng gi\u00fap m\u00ecnh b\u1edbt b\u1ecb cu\u1ed1n v\u00e0o:\n\n1. Ch\u1ea1m v\u00e0o **Menu**.\n2. Ch\u1ea1m **C\u00e0i \u0111\u1eb7t & quy\u1ec1n ri\u00eang t\u01b0**, r\u1ed3i **C\u00e0i \u0111\u1eb7t**.\n3. Trong **T\u00f9y ch\u1ecdn** (Preferences), ch\u1ea1m **File ph\u01b0\u01a1ng ti\u1ec7n** (Media).\n4. Trong **T\u1ef1 \u0111\u1ed9ng ph\u00e1t** (Autoplay), ch\u1ecdn **Kh\u00f4ng bao gi\u1edd t\u1ef1 \u0111\u1ed9ng ph\u00e1t video** (Never Autoplay Videos).\n\nN\u1ebfu kh\u00f4ng th\u1ea5y m\u1ee5c File ph\u01b0\u01a1ng ti\u1ec7n, Facebook khuy\u00ean c\u1eadp nh\u1eadt \u1ee9ng d\u1ee5ng tr\u01b0\u1edbc. Sau khi b\u1eadt, video trong B\u1ea3ng feed s\u1ebd \u0111\u1ee9ng y\u00ean cho t\u1edbi khi b\u1ea1n ch\u1ea1m v\u00e0o. Th\u01b0\u1edbc phim v\u1eabn n\u1eb1m \u0111\u00f3.\n\n## C\u00f2n tab Video th\u00ec sao?\n\nM\u00ecnh kh\u00f4ng t\u00ecm th\u1ea5y h\u01b0\u1edbng d\u1eabn g\u1ee1 tab Video trong tr\u1ee3 gi\u00fap c\u1ee7a Facebook, n\u00ean kh\u00f4ng ghi b\u01b0\u1edbc l\u00e0m \u1edf \u0111\u00e2y. C\u00e1c trang m\u00ecnh \u0111\u00e3 \u0111\u1ecdc ch\u1ec9 n\u00f3i th\u01b0\u1edbc phim c\u00f3 th\u1ec3 xu\u1ea5t hi\u1ec7n trong Video.\n\n## C\u00f2n Th\u1eddi gian s\u1eed d\u1ee5ng c\u1ee7a iPhone?\n\nB\u1ea1n c\u00f3 th\u1ec3 \u0111\u1eb7t gi\u1edbi h\u1ea1n cho c\u1ea3 \u1ee9ng d\u1ee5ng Facebook trong C\u00e0i \u0111\u1eb7t \u203a Th\u1eddi gian s\u1eed d\u1ee5ng. Nh\u01b0ng gi\u1edbi h\u1ea1n \u0111\u00f3 \u00e1p d\u1ee5ng cho c\u1ea3 \u1ee9ng d\u1ee5ng: h\u1ebft gi\u1edd l\u00e0 nh\u00f3m l\u1edbp, Th\u00f4ng b\u00e1o v\u00e0 m\u1ecdi th\u1ee9 kh\u00e1c c\u0169ng b\u1ecb ch\u1eb7n theo. Messenger l\u00e0 \u1ee9ng d\u1ee5ng ri\u00eang n\u00ean kh\u00f4ng b\u1ecb \u1ea3nh h\u01b0\u1edfng, c\u00f2n nh\u1eefng g\u00ec n\u1eb1m trong app Facebook th\u00ec c\u00f3. N\u1ebfu b\u1ea1n ch\u1ec9 mu\u1ed1n b\u1ecf Reels m\u00e0 v\u1eabn \u0111\u1ecdc \u0111\u01b0\u1ee3c nh\u00f3m, c\u00e1ch n\u00e0y h\u01a1i qu\u00e1 tay.\n\n## M\u1ed9t l\u1ef1a ch\u1ecdn kh\u00e1c: \u1ee9ng d\u1ee5ng m\u00ecnh l\u00e0m\n\nM\u00ecnh l\u00e0 Ayumu Kitabayashi, l\u1eadp tr\u00ecnh vi\u00ean m\u1ed9t m\u00ecnh, v\u00e0 m\u00ecnh \u0111\u00e3 l\u00e0m m\u1ed9t \u1ee9ng d\u1ee5ng iPhone t\u00ean **minulo** v\u00ec \u0111\u00fang v\u1ea5n \u0111\u1ec1 n\u00e0y. M\u00ecnh n\u00f3i r\u00f5 l\u00e0 app c\u1ee7a m\u00ecnh \u0111\u1ec3 b\u1ea1n t\u1ef1 c\u00e2n nh\u1eafc.\n\nminulo m\u1edf trang web ch\u00ednh th\u1ee9c c\u1ee7a Facebook ngay trong \u1ee9ng d\u1ee5ng. \u1ede bi\u1ec3u t\u01b0\u1ee3ng b\u00e1nh r\u0103ng c\u1ea1nh Facebook, b\u1ea1n c\u00f3 th\u1ec3 b\u1eadt **\u1ea8n Reels, Watch v\u00e0 Marketplace** v\u00e0 **\u1ea8n b\u00e0i vi\u1ebft g\u1ee3i \u00fd**, ngo\u00e0i ra c\u00f3 th\u1ec3 \u1ea9n **B\u1ea3ng tin trang ch\u1ee7** v\u00e0 **Bi\u1ec3u ng\u1eef \"M\u1edf \u1ee9ng d\u1ee5ng\"**. Th\u00f4ng b\u00e1o, Tin nh\u1eafn, B\u1ea1n b\u00e8 v\u00e0 b\u1ea3ng feed m\u1edf th\u1eb3ng t\u1eeb m\u00e0n h\u00ecnh ch\u00ednh c\u1ee7a minulo. Vi\u1ec7c \u1ea9n l\u00e0 mi\u1ec5n ph\u00ed. Instagram v\u00e0 YouTube c\u0169ng d\u00f9ng \u0111\u01b0\u1ee3c theo c\u00e1ch t\u01b0\u01a1ng t\u1ef1 (\u1ea9n Reels, Shorts, v\u1eabn gi\u1eef tin nh\u1eafn).\n\nNh\u1eefng g\u00ec minulo **kh\u00f4ng** l\u00e0m \u0111\u01b0\u1ee3c:\n\n- \u1ee8ng d\u1ee5ng Facebook ch\u00ednh th\u1ee9c kh\u00f4ng thay \u0111\u1ed5i. M\u1edf app Facebook th\u00ec Reels v\u1eabn c\u00f2n.\n- minulo c\u00f3 th\u1ec3 ch\u1eb7n app ch\u00ednh th\u1ee9c b\u1eb1ng Th\u1eddi gian s\u1eed d\u1ee5ng, mi\u1ec5n ph\u00ed t\u1ed1i \u0111a 2 gi\u1edd m\u1ed7i l\u1ea7n ch\u1eb7n. Trong l\u00fac app b\u1ecb ch\u1eb7n, th\u00f4ng b\u00e1o c\u1ee7a n\u00f3 kh\u00f4ng \u0111\u1ebfn, v\u00e0 minulo c\u0169ng kh\u00f4ng t\u1ef1 g\u1eedi th\u00f4ng b\u00e1o n\u00e0o thay.\n- L\u1ecbch theo ng\u00e0y gi\u1edd, ch\u1eb7n l\u00e2u h\u01a1n, Ch\u1ebf \u0111\u1ed9 nghi\u00eam ng\u1eb7t v\u00e0 nhi\u1ec1u danh s\u00e1ch ch\u1eb7n n\u1eb1m trong b\u1ea3n Pro (tr\u1ea3 ph\u00ed).\n- Kh\u00f4ng c\u00f3 b\u1ea3n cho Android hay iPad.\n\n## T\u00f3m l\u1ea1i\n\n- Facebook kh\u00f4ng c\u00f3 c\u00e0i \u0111\u1eb7t t\u1eaft Reels; m\u1ecdi video gi\u1edd \u0111\u1ec1u l\u00e0 th\u01b0\u1edbc phim.\n- Kh\u00f4ng quan t\u00e2m, \u1ea8n th\u01b0\u1edbc phim v\u00e0 B\u1ecf theo d\u00f5i gi\u00fap th\u1ea5y \u00edt h\u01a1n, nh\u01b0ng t\u00e1c d\u1ee5ng ch\u1eadm v\u00e0 phai d\u1ea7n.\n- Kh\u00f4ng bao gi\u1edd t\u1ef1 \u0111\u1ed9ng ph\u00e1t video gi\u00fap b\u1edbt b\u1ecb cu\u1ed1n, nh\u01b0ng kh\u00f4ng x\u00f3a Reels.\n- Gi\u1edbi h\u1ea1n b\u1eb1ng Th\u1eddi gian s\u1eed d\u1ee5ng th\u00ec ch\u1eb7n c\u1ea3 app, k\u1ec3 c\u1ea3 nh\u00f3m.\n\nTrang \u0111\u1ea7y \u0111\u1ee7, c\u00f3 link t\u1edbi c\u00e1c trang tr\u1ee3 gi\u00fap c\u1ee7a Facebook, \u1edf \u0111\u00e2y:\nhttps:\/\/minulo.app\/vi\/facebook-reels-off?ref=viblo-vi-fbreels-1025n","published_at":"2026-10-25T12:15:33.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T16:32:03.000000Z","edited_at":"2026-10-25T12:15:00.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":7,"points":0,"views_count":11,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/3eca7fc6-e1ef-4a7f-96e8-5d66da51dcd4.png","user":{"data":{"id":226329,"url":"https:\/\/viblo.asia\/u\/barcaak1011","avatar":null,"name":"ayumu kitabayashi","username":"barcaak1011","followers_count":0,"reputation":0,"posts_count":4,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"facebook","name":"Facebook"},{"slug":"iphone","name":"iPhone"},{"slug":"reels","name":"Reels"}]},"commentators":{"data":[]}},{"id":109669,"title":"C\u1ea5u h\u00ecnh virtual box cho ph\u00e1t tri\u1ec3n ph\u1ea7n m\u1ec1m","slug":"ZoJjejDy4Y7","url":"https:\/\/viblo.asia\/p\/cau-hinh-virtual-box-cho-phat-trien-phan-mem-ZoJjejDy4Y7","user_id":150568,"moderation":null,"transliterated":"cau-hinh-virtual-box-cho-phat-trien-phan-mem","contents_short":"How to get it ez to use vm as a \"environment\"\nCh\u00e0o m\u1ecdi ng\u01b0\u1eddi, \u0111\u00e2y l\u00e0 b\u00e0i vi\u1ebft \u0111\u1ea7u ti\u00ean c\u1ee7a m\u00ecnh v\u00e0 h\u00f4m nay m\u00ecnh s\u1ebd chia s\u1ebb m\u1ed9t s\u1ed1 th\u1ee9 li\u00ean quan t\u1edbi vi\u1ec7c c\u1ea5u h\u00ecnh virtualbox sao cho thu\u1eadn ti\u1ec7n trong vi\u1ec7c code ki\u1ebft c\u00e1c th\u1ee9 tr\u00ean vm. \u00c0 h\u1ec7 \u0111i\u1ec1u h\u00e0nh m\u00ecnh \u0111ang s\u1eed d\u1ee5ng l\u00e0 window tr\u00ean m\u00e1y host v\u00e0 ubuntu 22.04 cho m\u00e1y vm.\nVi\u1ec7c c\u00e0i m\u1ed9t m\u1edb th\u1ee9 l\u00ean m\u00e1y win v\u00e0 g\u1eb7p l\u1ed7i xung \u0111\u1ed9t package trong l\u00fac code and run...","contents":"# How to get it ez to use vm as a \"environment\"\nCh\u00e0o m\u1ecdi ng\u01b0\u1eddi, \u0111\u00e2y l\u00e0 b\u00e0i vi\u1ebft \u0111\u1ea7u ti\u00ean c\u1ee7a m\u00ecnh v\u00e0 h\u00f4m nay m\u00ecnh s\u1ebd chia s\u1ebb m\u1ed9t s\u1ed1 th\u1ee9 li\u00ean quan t\u1edbi vi\u1ec7c c\u1ea5u h\u00ecnh virtualbox sao cho thu\u1eadn ti\u1ec7n trong vi\u1ec7c code ki\u1ebft c\u00e1c th\u1ee9 tr\u00ean vm. \u00c0 h\u1ec7 \u0111i\u1ec1u h\u00e0nh m\u00ecnh \u0111ang s\u1eed d\u1ee5ng l\u00e0 window tr\u00ean m\u00e1y host v\u00e0 ubuntu 22.04 cho m\u00e1y vm.\nVi\u1ec7c c\u00e0i m\u1ed9t m\u1edb th\u1ee9 l\u00ean m\u00e1y win v\u00e0 g\u1eb7p l\u1ed7i xung \u0111\u1ed9t package trong l\u00fac code and run (v\u00ed d\u1ee5 nh\u01b0 python ch\u1eb3ng h\u1ea1n) l\u00e0 th\u01b0\u1eddng th\u1ea5y, v\u00e0 c\u1ea3 vi\u1ec7c install\/uninstall c\u00e1c phi\u00ean b\u1ea3n th\u01b0\u1eddng phi\u1ec1n ph\u1ee9c n\u1eefa. N\u00ean d\u00f9ng virtualbox \u0111\u1ec3 c\u00e0i \u0111\u1eb7t m\u00f4i tr\u01b0\u1eddng l\u00e0m vi\u1ec7c l\u00e0 \u0111\u1ea5ng c\u1ee9u tinh cho nh\u1eefng v\u1ea5n \u0111\u1ec1 n\u00e0y. V\u00e0 v\u1ea5n \u0111\u1ec1 c\u0169ng ph\u00e1t sinh khi m\u00e0 run m\u1ed9t web local tr\u00ean vm th\u00ec l\u00ean tr\u00ean m\u00e1y window host ch\u1ea3 th\u1ea5y n\u00f3 \u0111\u00e2u =))). L\u00fac n\u00e0y th\u00ec l\u1ea1i c\u1ea7n ch\u00fang ta nh\u1ea3y v\u00e0o c\u1ea5u h\u00ecnh l\u1ea1i network, port c\u00e1c th\u1ee9 - \u0111i\u1ec1u m\u00e0 m\u1ecdi ng\u01b0\u1eddi \u00edt khi \u0111\u1ec3 \u00fd, nh\u1ea5t l\u00e0 trong th\u1eddi \u0111\u1ea1i vibe coding tr\u00e0n lan th\u1ebf n\u00e0y. D\u00e0i d\u00f2ng \u0111\u1ee7 r\u1ed3i, \u0111i v\u00e0o chuy\u1ec7n ch\u00ednh n\u00e0o.\n# Hi\u1ec3u \"network\" c\u1ee7a virtualbox\n\u1ede \u0111\u00e2y m\u00ecnh ch\u1ec9 \u0111ang n\u00f3i t\u1edbi c\u00e1ch ch\u00fang ta c\u00f3 th\u1ec3 \"port\" m\u1ed9t process ra ngo\u00e0i m\u00e1y window host. V\u00e0 m\u1ed9t VM \u0111\u01b0\u1ee3c c\u00e0i \u0111\u1eb7t tr\u00ean virtualbox s\u1ebd c\u00f3 m\u1ed9t s\u1ed1 network mode:\n- NAT\n- Bridge Adapter\n- Host-only adapter\n- NAT network \n- NAT + Host-only\nT\u01b0\u01a1ng \u1ee9ng v\u1edbi nh\u1eefng mode n\u00e0y, \u0111i\u1ec1u ch\u00fang ta c\u1ea7n bi\u1ebft khi m\u00e0 mu\u1ed1n truy c\u1eadp c\u00e1i process (web) m\u00e0 ch\u00fang ta \u0111\u00e3 start b\u00ean trong con m\u00e1y VM virtualbox l\u00e0 c\u00e1ch m\u00e0 m\u1ed7i mode s\u1ebd ho\u1ea1t \u0111\u1ed9ng. V\u00ed d\u1ee5 nh\u01b0 b\u1ea1n c\u00f3 m\u1ed9t web \u0111\u01b0\u1ee3c start `http:\/\/localhost:4566`. V\u1eady c\u1ea7n l\u00e0m g\u00ec \u0111\u1ec3 c\u00f3 th\u1ec3 truy c\u1eadp b\u00ean ngo\u00e0i tr\u00ecnh duy\u1ec7t m\u00e1y window host. C\u00e2u tr\u1ea3 l\u1eddi l\u00e0 tu\u1ef3 v\u00e0o c\u00e1ch m\u00e0 b\u1ea1n s\u1eed d\u1ee5ng t\u1eebng mode.\n- V\u1edbi NAT v\u00e0 NAT network , b\u1ea1n kh\u00f4ng th\u1ec3 truy c\u1eadp tr\u1ef1c ti\u1ebfp qua IP `http:\/\/localhost:4566` c\u1ee7a VM, l\u00fac n\u00e0y s\u1ebd c\u1ea7n c\u1ea5u h\u00ecnh th\u1ee7 c\u00f4ng th\u00f4ng qua port forwarding c\u1ee7a virtualbox\n- V\u1edbi NAT + Host-only, Bridge Adapter v\u00e0 Host-only Adapter th\u00ec m\u1ecdi th\u1ee9 \u0111\u01a1n gi\u1ea3n h\u01a1n khi ch\u1ec9 c\u1ea7n truy c\u1eadp theo \u0111\u00fang IP l\u00e0 \u0111\u01b0\u1ee3c\nV\u00ed d\u1ee5:\n![{B2FD277D-4E17-41D1-96B6-A9D88F2201E7}.png](https:\/\/images.viblo.asia\/ccfeb404-c79a-41a0-acb9-7c8dae401c26.png)\n# Chi ti\u1ebft h\u01a1n t\u00ed\n## N\u1ebfu VM \u0111ang s\u1eed d\u1ee5ng NAT\nB\u1ea1n c\u1ea7n c\u1ea5u h\u00ecnh port forwarding. Trong VirtualBox: VM \u2192 Settings \u2192 Network \u2192 Adapter 1 \u2192 Advanced \u2192 Port Forwarding\n![{CF08A684-F9B3-4E73-8FDB-30D27CEEC228}.png](https:\/\/images.viblo.asia\/e9f92a61-7903-4006-92c8-f946e2aa916e.png)\nSau \u0111\u00f3, t\u1eeb Windows, truy c\u1eadp: `http:\/\/localhost:4566`\nVirtualBox s\u1ebd chuy\u1ec3n TCP connection t\u1eeb Windows v\u00e0o port 4566 c\u1ee7a Ubuntu VM.\n## N\u1ebfu s\u1eed d\u1ee5ng Bridged Adapter ho\u1eb7c Host-only\nB\u1ea1n kh\u00f4ng c\u1ea7n VirtualBox port forwarding.\nV\u00ed d\u1ee5 Ubuntu VM c\u00f3 IP `192.168.1.100`, b\u1ea1n truy c\u1eadp t\u1eeb Windows: `http:\/\/192.168.1.100:4566`\nNh\u01b0ng c\u00f3 m\u1ed9t \u0111i\u1ec1u ki\u1ec7n quan tr\u1ecdng: Docker ph\u1ea3i publish port ra network interface c\u1ee7a VM.\n\nV\u00ed d\u1ee5:\n`docker run -d \n  --name floci \n  -p 4566:4566 \n  <floci-image>`\n\nL\u1ec7nh `-p 4566:4566` m\u1eb7c \u0111\u1ecbnh publish tr\u00ean c\u00e1c \u0111\u1ecba ch\u1ec9 host th\u00edch h\u1ee3p, th\u01b0\u1eddng l\u00e0 `0.0.0.0:4566`\nN\u1ebfu b\u1ea1n ch\u1ea1y:\n`docker run -p 127.0.0.1:4566:4566 ...`\nth\u00ec ch\u1ec9 VM truy c\u1eadp \u0111\u01b0\u1ee3c th\u00f4ng qua localhost c\u1ee7a ch\u00ednh VM; Windows kh\u00f4ng th\u1ec3 truy c\u1eadp tr\u1ef1c ti\u1ebfp qua IP c\u1ee7a VM.\nB\u1ea1n c\u00f3 th\u1ec3 ki\u1ec3m tra:\n`docker ps && ss -lnt | grep 4566`\nL\u01b0u \u00fd: Firewall trong Ubuntu c\u0169ng c\u00f3 th\u1ec3 ch\u1eb7n k\u1ebft n\u1ed1i t\u1eeb Windows.\n# C\u1ea5u h\u00ecnh m\u00ecnh x\u00e0i\nM\u00ecnh s\u1eed d\u1ee5ng 2 Network Adapters:\n- Adapter 1 \u2014 NAT: Cho VM truy c\u1eadp Internet, t\u1ea3i Docker images, c\u00e0i packages.\n- Adapter 2 \u2014 Host-only Adapter: Cho m\u00e1y window host giao ti\u1ebfp tr\u1ef1c ti\u1ebfp v\u1edbi c\u00e1c service trong VM.\nV\u1edbi c\u00e1ch n\u00e0y, m\u00ecnh kh\u00f4ng c\u1ea7n t\u1ea1o m\u1ed9t port-forwarding rule m\u1ed7i khi tri\u1ec3n khai th\u00eam service m\u1edbi","published_at":"2026-10-25T11:32:46.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T17:00:31.000000Z","edited_at":"2026-10-25T11:32:11.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":4,"points":0,"views_count":8,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/e7de85e3-224f-4e68-8124-439571f76f3b.png","user":{"data":{"id":150568,"url":"https:\/\/viblo.asia\/u\/YuSato","avatar":"88d05c9a-cb3d-4b80-8074-ba620b1e7a9b.jpg","name":"Qu\u1ed1c Quang V\u00f5","username":"YuSato","followers_count":0,"reputation":0,"posts_count":0,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"devops","name":"DevOps"},{"slug":"virtualbox","name":"VirtualBox"}]},"commentators":{"data":[]}},{"id":109670,"title":"Function Calling: So s\u00e1nh Responses API v\u00e0 Chat Completions","slug":"gjLN0ZR8432","url":"https:\/\/viblo.asia\/p\/function-calling-so-sanh-responses-api-va-chat-completions-gjLN0ZR8432","user_id":226961,"moderation":null,"transliterated":"function-calling-so-sanh-responses-api-va-chat-completions","contents_short":"B\u00e0i vi\u1ebft n\u00e0y \u0111\u01b0\u1ee3c d\u1ecbch v\u00e0 bi\u00ean t\u1eadp t\u1eeb b\u00e0i g\u1ed1c ti\u1ebfng Anh tr\u00ean blog c\u1ee7a Modelflare.\n\nSo s\u00e1nh \u1edf m\u1ee9c wire format gi\u1eefa \u0111\u1ecbnh ngh\u0129a function, Call ID, message k\u1ebft qu\u1ea3, streaming argument, ph\u00e2n quy\u1ec1n (authorization), t\u00ednh idempotent v\u00e0 kh\u1ea3 n\u0103ng t\u01b0\u01a1ng th\u00edch c\u1ee7a route.\n\nC\u1ea3 Responses API l\u1eabn Chat Completions \u0111\u1ec1u c\u00f3 th\u1ec3 y\u00eau c\u1ea7u \u1ee9ng d\u1ee5ng ch\u1ea1y m\u1ed9t function, nh\u01b0ng m\u1ed7i b\u00ean bi\u1ec3u di\u1ec5n tool loop theo c\u00e1ch kh\u00e1c nh...","contents":"B\u00e0i vi\u1ebft n\u00e0y \u0111\u01b0\u1ee3c d\u1ecbch v\u00e0 bi\u00ean t\u1eadp t\u1eeb b\u00e0i g\u1ed1c ti\u1ebfng Anh tr\u00ean [blog c\u1ee7a Modelflare](https:\/\/modelflare.dev\/articles\/function-calling-responses-vs-chat-completions).\n\nSo s\u00e1nh \u1edf m\u1ee9c wire format gi\u1eefa \u0111\u1ecbnh ngh\u0129a function, Call ID, message k\u1ebft qu\u1ea3, streaming argument, ph\u00e2n quy\u1ec1n (authorization), t\u00ednh idempotent v\u00e0 kh\u1ea3 n\u0103ng t\u01b0\u01a1ng th\u00edch c\u1ee7a route.\n\nC\u1ea3 Responses API l\u1eabn Chat Completions \u0111\u1ec1u c\u00f3 th\u1ec3 y\u00eau c\u1ea7u \u1ee9ng d\u1ee5ng ch\u1ea1y m\u1ed9t function, nh\u01b0ng m\u1ed7i b\u00ean bi\u1ec3u di\u1ec5n tool loop theo c\u00e1ch kh\u00e1c nhau. Chat Completions \u0111\u1eb7t \u0111\u1ecbnh ngh\u0129a tool trong `tools[].function`, tr\u1ea3 v\u1ec1 `message.tool_calls` v\u00e0 nh\u1eadn k\u1ebft qu\u1ea3 d\u01b0\u1edbi d\u1ea1ng message c\u00f3 `role: \"tool\"`. Responses API d\u00f9ng \u0111\u1ecbnh ngh\u0129a function d\u1ea1ng ph\u1eb3ng (flat), tr\u1ea3 v\u1ec1 c\u00e1c output item c\u00f3 ki\u1ec3u `function_call` v\u00e0 nh\u1eadn c\u00e1c item `function_call_output` \u0111\u01b0\u1ee3c li\u00ean k\u1ebft b\u1eb1ng `call_id`.\n\nModel kh\u00f4ng t\u1ef1 ch\u1ea1y function c\u1ee7a \u1ee9ng d\u1ee5ng. Ch\u00ednh code c\u1ee7a b\u1ea1n ph\u1ea3i validate c\u00e1c argument \u0111\u01b0\u1ee3c \u0111\u1ec1 xu\u1ea5t, ph\u00e2n quy\u1ec1n cho thao t\u00e1c, th\u1ef1c thi \u0111\u00fang nh\u01b0 \u00fd \u0111\u1ecbnh, tr\u1ea3 k\u1ebft qu\u1ea3 v\u1ec1 cho model v\u00e0 ng\u0103n side effect b\u1ecb l\u1eb7p l\u1ea1i khi request \u0111\u01b0\u1ee3c retry.\n\n## Tool loop g\u1ed3m b\u1ed1n b\u01b0\u1edbc\n\nJSON c\u1ee7a t\u1eebng endpoint kh\u00e1c nhau, nh\u01b0ng state machine c\u1ee7a \u1ee9ng d\u1ee5ng th\u00ec gi\u1ed1ng nhau:\n\n```text\n1. Khai b\u00e1o function \u0111\u01b0\u1ee3c ph\u00e9p g\u1ecdi v\u00e0 schema cho argument c\u1ee7a n\u00f3\n2. Nh\u1eadn m\u1ed9t ho\u1eb7c nhi\u1ec1u l\u1eddi g\u1ecdi function do model \u0111\u1ec1 xu\u1ea5t\n3. Validate, ph\u00e2n quy\u1ec1n v\u00e0 th\u1ef1c thi t\u1eebng l\u1eddi g\u1ecdi trong code \u1ee9ng d\u1ee5ng\n4. Tr\u1ea3 v\u1ec1 t\u1eebng k\u1ebft qu\u1ea3 k\u00e8m correlation ID c\u1ee7a l\u1eddi g\u1ecdi \u0111\u00f3\n```\n\nCh\u1ec9 sau b\u01b0\u1edbc b\u1ed1n, model m\u1edbi c\u00f3 th\u1ec3 \u0111\u01b0a ra c\u00e2u tr\u1ea3 l\u1eddi d\u1ef1a tr\u00ean k\u1ebft qu\u1ea3 c\u1ee7a tool. N\u1ebfu model y\u00eau c\u1ea7u th\u00eam tool kh\u00e1c, v\u00f2ng l\u1eb7p l\u1eb7p l\u1ea1i v\u1edbi m\u1ed9t Call ID m\u1edbi.\n\n[H\u01b0\u1edbng d\u1eabn Function Calling c\u1ee7a OpenAI](https:\/\/developers.openai.com\/api\/docs\/guides\/function-calling) m\u00f4 t\u1ea3 \u0111\u00e2y l\u00e0 m\u1ed9t qu\u00e1 tr\u00ecnh trao \u0111\u1ed5i nhi\u1ec1u b\u01b0\u1edbc. Coi l\u1eddi g\u1ecdi tool \u0111\u1ea7u ti\u00ean l\u00e0 c\u00e2u tr\u1ea3 l\u1eddi cu\u1ed1i c\u00f9ng l\u00e0 m\u1ed9t l\u1ed7i t\u00edch h\u1ee3p r\u1ea5t ph\u1ed5 bi\u1ebfn.\n\n## So s\u00e1nh contract \u1edf m\u1ee9c wire format\n\nKh\u00e1c bi\u1ec7t ch\u00ednh n\u1eb1m \u1edf c\u1ea5u tr\u00fac ch\u1ee9 kh\u00f4ng ph\u1ea3i \u1edf kh\u00e1i ni\u1ec7m.\n\n| Kh\u00eda c\u1ea1nh | Responses API | Chat Completions |\n| --- | --- | --- |\n| \u0110\u1ecbnh ngh\u0129a function | Item ph\u1eb3ng trong `tools[]` v\u1edbi `name`, `description`, `parameters`, `strict` | Item trong `tools[]` v\u1edbi c\u00e1c field \u0111\u00f3 l\u1ed3ng b\u00ean trong `function` |\n| L\u1eddi g\u1ecdi do model \u0111\u1ec1 xu\u1ea5t | Output item c\u00f3 ki\u1ec3u `function_call` | Ph\u1ea7n t\u1eed `tool_calls[]` trong message c\u1ee7a assistant |\n| \u0110\u1ecbnh danh \u0111\u1ec3 \u0111\u1ed1i chi\u1ebfu | `call_id` | `id` c\u1ee7a tool call, \u0111\u01b0\u1ee3c tr\u1ea3 l\u1ea1i d\u01b0\u1edbi d\u1ea1ng `tool_call_id` |\n| T\u00ean function | `function_call.name` | `tool_calls[].function.name` |\n| Argument | Chu\u1ed7i JSON trong `function_call.arguments` | Chu\u1ed7i JSON trong `tool_calls[].function.arguments` |\n| K\u1ebft qu\u1ea3 tool | Input item `function_call_output` | Message c\u00f3 `role: \"tool\"` |\n| D\u1ea1ng streaming argument th\u01b0\u1eddng g\u1eb7p | Event delta argument c\u00f3 ki\u1ec3u | C\u00e1c m\u1ea3nh `delta.tool_calls[]` c\u00f3 \u0111\u00e1nh index |\n| Text cu\u1ed1i c\u00f9ng | Output item c\u00f3 ki\u1ec3u v\u00e0 helper l\u1ea5y output text | `choices[0].message.content` |\n\n\u0110\u1eebng gh\u00e9p l\u1eddi g\u1ecdi v\u1edbi k\u1ebft qu\u1ea3 theo v\u1ecb tr\u00ed trong m\u1ea3ng. C\u00e1c l\u1eddi g\u1ecdi song song v\u00e0 chunk streaming c\u00f3 th\u1ec3 \u0111\u1ebfn theo th\u1ee9 t\u1ef1 kh\u00e1c v\u1edbi th\u1ee9 t\u1ef1 \u1ee9ng d\u1ee5ng x\u1eed l\u00fd xong. Call ID t\u01b0\u1eddng minh m\u1edbi l\u00e0 kh\u00f3a gh\u00e9p (join key) \u1ed5n \u0111\u1ecbnh.\n\n## \u0110\u1ecbnh ngh\u0129a m\u1ed9t function schema strict\n\nC\u00e1c v\u00ed d\u1ee5 d\u01b0\u1edbi \u0111\u00e2y expose m\u1ed9t function ch\u1ec9 \u0111\u1ecdc l\u00e0 `get_delivery_status`. Model c\u00f3 th\u1ec3 h\u1ecfi tr\u1ea1ng th\u00e1i \u0111\u01a1n h\u00e0ng, nh\u01b0ng kh\u00f4ng th\u1ec3 s\u1eeda \u0111\u01a1n, ho\u00e0n ti\u1ec1n hay truy c\u1eadp storage t\u00f9y \u00fd.\n\nSchema c\u1ee7a argument \u0111\u01b0\u1ee3c c\u1ed1 \u00fd gi\u1edbi h\u1ea1n ch\u1eb7t:\n\n```json\n{\n  \"type\": \"object\",\n  \"properties\": {\n    \"order_id\": {\n      \"type\": \"string\",\n      \"pattern\": \"^ORDER-[0-9]{4}$\"\n    }\n  },\n  \"required\": [\n    \"order_id\"\n  ],\n  \"additionalProperties\": false\n}\n```\n\n`strict: true` y\u00eau c\u1ea7u model (n\u1ebfu c\u00f3 h\u1ed7 tr\u1ee3) tu\u00e2n th\u1ee7 schema argument c\u1ee7a function. D\u00f9 v\u1eady, \u1ee9ng d\u1ee5ng v\u1eabn ph\u1ea3i parse v\u00e0 validate JSON tr\u01b0\u1edbc khi th\u1ef1c thi. M\u1ee9c h\u1ed7 tr\u1ee3 `pattern` v\u00e0 c\u00e1c t\u00ednh n\u0103ng JSON Schema kh\u00e1c c\u00f3 th\u1ec3 kh\u00e1c nhau gi\u1eefa c\u00e1c model ho\u1eb7c provider, n\u00ean b\u01b0\u1edbc ki\u1ec3m tra t\u01b0\u01a1ng th\u00edch d\u00f9ng cho [Structured Outputs](https:\/\/modelflare.dev\/articles\/structured-outputs-openai-compatible-api) c\u0169ng \u00e1p d\u1ee5ng cho argument c\u1ee7a function.\n\n## C\u00e0i \u0111\u1eb7t v\u00f2ng l\u1eb7p v\u1edbi Responses API\n\nV\u00ed d\u1ee5 JavaScript n\u00e0y gi\u1eef cho qu\u00e1 tr\u00ecnh trao \u0111\u1ed5i l\u00e0 stateless b\u1eb1ng c\u00e1ch g\u1eedi l\u1ea1i c\u00e1c output item c\u1ee7a model c\u00f9ng v\u1edbi k\u1ebft qu\u1ea3 function. V\u00ed d\u1ee5 d\u00f9ng m\u1ed9t function c\u1ee5c b\u1ed9 c\u00f3 t\u00ednh t\u1ea5t \u0111\u1ecbnh (deterministic) \u0111\u1ec3 lu\u1ed3ng \u0111i\u1ec1u khi\u1ec3n hi\u1ec7n r\u00f5 m\u00e0 kh\u00f4ng c\u1ea7n th\u00eam m\u1ed9t API b\u00ean ngo\u00e0i n\u00e0o kh\u00e1c.\n\n```javascript\nimport OpenAI from \"openai\";\n\nconst client = new OpenAI({\n  apiKey: process.env.MODELFLARE_API_KEY,\n  baseURL: \"https:\/\/modelflare.dev\/v1\",\n});\n\nconst model = process.env.MODEL_ID;\nif (!model) throw new Error(\"MODEL_ID is required\");\n\nconst orders = new Map([\n  [\"ORDER-1001\", { status: \"in_transit\", eta: \"2026-08-06\" }],\n]);\n\nconst tools = [\n  {\n    type: \"function\",\n    name: \"get_delivery_status\",\n    description: \"Return the current delivery status for one order.\",\n    parameters: {\n      type: \"object\",\n      properties: {\n        order_id: { type: \"string\", pattern: \"^ORDER-[0-9]{4}$\" },\n      },\n      required: [\"order_id\"],\n      additionalProperties: false,\n    },\n    strict: true,\n  },\n];\n\nfunction executeTool(name, rawArguments) {\n  if (name !== \"get_delivery_status\") {\n    throw new Error(`Tool is not allowed: ${name}`);\n  }\n\n  const args = JSON.parse(rawArguments);\n  if (!\/^ORDER-[0-9]{4}$\/.test(args.order_id)) {\n    throw new Error(\"Invalid order_id\");\n  }\n\n  return orders.get(args.order_id) ?? { status: \"not_found\" };\n}\n\nconst first = await client.responses.create({\n  model,\n  input: \"Where is ORDER-1001?\",\n  tools,\n  parallel_tool_calls: false,\n});\n\nconst calls = first.output.filter((item) => item.type === \"function_call\");\nif (calls.length === 0) {\n  console.log(first.output_text);\n  process.exit(0);\n}\n\nconst toolOutputs = calls.map((call) => ({\n  type: \"function_call_output\",\n  call_id: call.call_id,\n  output: JSON.stringify(executeTool(call.name, call.arguments)),\n}));\n\nconst final = await client.responses.create({\n  model,\n  input: [...first.output, ...toolOutputs],\n  tools,\n  parallel_tool_calls: false,\n});\n\nconsole.log(final.output_text);\n```\n\nN\u1ebfu c\u1ea7n t\u00edch h\u1ee3p c\u00f3 tr\u1ea1ng th\u00e1i (stateful), Responses API c\u0169ng cho ph\u00e9p ti\u1ebfp t\u1ee5c t\u1eeb m\u1ed9t response tr\u01b0\u1edbc \u0111\u00f3 khi route v\u00e0 ch\u00ednh s\u00e1ch l\u01b0u tr\u1eef cho ph\u00e9p. V\u00ed d\u1ee5 stateless gi\u00fap to\u00e0n b\u1ed9 l\u1ecbch s\u1eed h\u1ed9i tho\u1ea1i hi\u1ec7n r\u00f5 v\u00e0 tr\u00e1nh gi\u1ea3 \u0111\u1ecbnh r\u1eb1ng m\u1ecdi route t\u01b0\u01a1ng th\u00edch OpenAI \u0111\u1ec1u l\u01b0u tr\u1ea1ng th\u00e1i response.\n\nC\u00e1c field quan tr\u1ecdng nh\u1ea5t l\u00e0 `call.call_id` trong output c\u1ee7a model v\u00e0 `call_id` t\u01b0\u01a1ng \u1ee9ng trong `function_call_output`. Tr\u1ea3 k\u1ebft qu\u1ea3 v\u1edbi ID sai s\u1ebd l\u00e0m d\u1eef li\u1ec7u b\u1ecb t\u00e1ch r\u1eddi kh\u1ecfi y\u00eau c\u1ea7u c\u1ee7a model.\n\n## C\u00e0i \u0111\u1eb7t v\u00f2ng l\u1eb7p v\u1edbi Chat Completions\n\nC\u00f9ng function \u0111\u00f3 c\u1ee7a \u1ee9ng d\u1ee5ng c\u00f3 th\u1ec3 d\u00f9ng v\u1edbi Chat Completions. \u0110\u1ecbnh ngh\u0129a tool v\u00e0 message k\u1ebft qu\u1ea3 d\u00f9ng l\u1edbp b\u1ecdc (wrapper) theo ki\u1ec3u Chat.\n\n```javascript\nimport OpenAI from \"openai\";\n\nconst client = new OpenAI({\n  apiKey: process.env.MODELFLARE_API_KEY,\n  baseURL: \"https:\/\/modelflare.dev\/v1\",\n});\n\nconst model = process.env.MODEL_ID;\nif (!model) throw new Error(\"MODEL_ID is required\");\n\nconst orders = new Map([\n  [\"ORDER-1001\", { status: \"in_transit\", eta: \"2026-08-06\" }],\n]);\n\nconst tools = [\n  {\n    type: \"function\",\n    function: {\n      name: \"get_delivery_status\",\n      description: \"Return the current delivery status for one order.\",\n      parameters: {\n        type: \"object\",\n        properties: {\n          order_id: { type: \"string\", pattern: \"^ORDER-[0-9]{4}$\" },\n        },\n        required: [\"order_id\"],\n        additionalProperties: false,\n      },\n      strict: true,\n    },\n  },\n];\n\nfunction executeTool(name, rawArguments) {\n  if (name !== \"get_delivery_status\") {\n    throw new Error(`Tool is not allowed: ${name}`);\n  }\n\n  const args = JSON.parse(rawArguments);\n  if (!\/^ORDER-[0-9]{4}$\/.test(args.order_id)) {\n    throw new Error(\"Invalid order_id\");\n  }\n\n  return orders.get(args.order_id) ?? { status: \"not_found\" };\n}\n\nconst messages = [\n  { role: \"user\", content: \"Where is ORDER-1001?\" },\n];\n\nconst first = await client.chat.completions.create({\n  model,\n  messages,\n  tools,\n  parallel_tool_calls: false,\n});\n\nconst assistant = first.choices[0].message;\nconst calls = assistant.tool_calls ?? [];\nif (calls.length === 0) {\n  console.log(assistant.content);\n  process.exit(0);\n}\n\nmessages.push(assistant);\nfor (const call of calls) {\n  const result = executeTool(call.function.name, call.function.arguments);\n  messages.push({\n    role: \"tool\",\n    tool_call_id: call.id,\n    content: JSON.stringify(result),\n  });\n}\n\nconst final = await client.chat.completions.create({\n  model,\n  messages,\n  tools,\n  parallel_tool_calls: false,\n});\n\nconsole.log(final.choices[0].message.content);\n```\n\n\u1ede \u0111\u00e2y, message \u0111\u1ea7u ti\u00ean c\u1ee7a assistant ph\u1ea3i \u0111\u01b0\u1ee3c th\u00eam v\u00e0o `messages` tr\u01b0\u1edbc c\u00e1c k\u1ebft qu\u1ea3 tool c\u1ee7a n\u00f3. M\u1ed7i k\u1ebft qu\u1ea3 d\u00f9ng `tool_call_id: call.id`. B\u1ecf s\u00f3t message ch\u1ee9a tool call c\u1ee7a assistant ho\u1eb7c tr\u1ea3 v\u1ec1 ID kh\u00f4ng kh\u1edbp s\u1ebd t\u1ea1o ra l\u1ecbch s\u1eed h\u1ed9i tho\u1ea1i kh\u00f4ng h\u1ee3p l\u1ec7.\n\n## Argument \u0111\u01b0\u1ee3c stream theo t\u1eebng m\u1ea3nh, kh\u00f4ng ph\u1ea3i JSON ho\u00e0n ch\u1ec9nh\n\n\u1ede ch\u1ebf \u0111\u1ed9 streaming, argument c\u1ee7a function c\u00f3 th\u1ec3 \u0111\u1ebfn theo t\u1eebng m\u1ea3nh. M\u1ed9t chunk ch\u1ee9a `{\"order` kh\u00f4ng ph\u1ea3i l\u00e0 JSON sai; n\u00f3 ch\u1ec9 l\u00e0 JSON ch\u01b0a ho\u00e0n ch\u1ec9nh.\n\nParser an to\u00e0n gi\u1eef m\u1ed9t buffer cho m\u1ed7i \u0111\u1ecbnh danh l\u1eddi g\u1ecdi:\n\n1. x\u00e1c \u0111\u1ecbnh l\u1eddi g\u1ecdi ho\u1eb7c slot l\u1eddi g\u1ecdi c\u00f3 index t\u1eeb event;\n2. n\u1ed1i t\u1eebng delta argument v\u00e0o buffer c\u1ee7a l\u1eddi g\u1ecdi \u0111\u00f3;\n3. ch\u1edd t\u00edn hi\u1ec7u argument done ho\u1eb7c completed c\u1ee7a endpoint;\n4. parse chu\u1ed7i ho\u00e0n ch\u1ec9nh \u0111\u00fang m\u1ed9t l\u1ea7n;\n5. ch\u1ec9 validate v\u00e0 th\u1ef1c thi sau khi \u0111\u00e3 ho\u00e0n t\u1ea5t.\n\nResponses API d\u00f9ng c\u00e1c event c\u00f3 ki\u1ec3u cho argument c\u1ee7a function call v\u00e0 cho output item. Chat Completions ph\u00e1t ra c\u00e1c m\u1ea3nh trong `choices[].delta.tool_calls[]`, trong \u0111\u00f3 index x\u00e1c \u0111\u1ecbnh ph\u1ea7n t\u1eed \u0111ang \u0111\u01b0\u1ee3c x\u00e2y d\u1ef1ng v\u00e0 tool call cu\u1ed1i c\u00f9ng mang ID \u1ed5n \u0111\u1ecbnh c\u1ee7a n\u00f3. \u0110\u1eebng th\u1ef1c thi function khi m\u1ea3nh \u0111\u1ea7u ti\u00ean v\u1eeba \u0111\u1ebfn.\n\n[AI API Streaming Guide](https:\/\/modelflare.dev\/articles\/ai-api-streaming-guide) gi\u1ea3i th\u00edch v\u00ec sao k\u1ebft n\u1ed1i, event \u0111\u1ea7u ti\u00ean, output h\u1eefu \u00edch \u0111\u1ea7u ti\u00ean, idle timeout v\u00e0 ho\u00e0n t\u1ea5t c\u1ea7n \u0111\u01b0\u1ee3c \u0111o ri\u00eang.\n\n## Th\u1ef1c thi tool an to\u00e0n v\u00e0 idempotent\n\nArgument strict c\u1ea3i thi\u1ec7n c\u1ea5u tr\u00fac ch\u1ee9 kh\u00f4ng c\u1ea3i thi\u1ec7n ph\u00e2n quy\u1ec1n. Tr\u01b0\u1edbc khi th\u1ef1c thi b\u1ea5t k\u1ef3 l\u1eddi g\u1ecdi n\u00e0o:\n\n- ch\u1ec9 cho ph\u00e9p c\u00e1c t\u00ean function \u0111\u00e3 \u0111\u0103ng k\u00fd;\n- parse argument v\u1edbi gi\u1edbi h\u1ea1n k\u00edch th\u01b0\u1edbc;\n- validate to\u00e0n b\u1ed9 schema trong code \u1ee9ng d\u1ee5ng;\n- ph\u00e2n quy\u1ec1n cho user ho\u1eb7c workload hi\u1ec7n t\u1ea1i tr\u00ean t\u00e0i nguy\u00ean \u0111\u01b0\u1ee3c y\u00eau c\u1ea7u;\n- t\u00e1ch tool ch\u1ec9 \u0111\u1ecdc kh\u1ecfi tool c\u00f3 side effect;\n- che (redact) secret v\u00e0 output nh\u1ea1y c\u1ea3m tr\u01b0\u1edbc khi tr\u1ea3 v\u1ec1 cho model;\n- \u0111\u1eb7t deadline v\u00e0 gi\u1edbi h\u1ea1n s\u1ed1 l\u1ea7n retry \u1edf downstream;\n- ghi l\u1ea1i m\u1ed9t tham chi\u1ebfu thao t\u00e1c an to\u00e0n, kh\u00f4ng ghi secret hay n\u1ed9i dung ri\u00eang t\u01b0 d\u1ea1ng th\u00f4.\n\nV\u1edbi tool c\u00f3 side effect, h\u00e3y d\u00f9ng idempotency key \u0111\u01b0\u1ee3c suy ra t\u1eeb m\u1ed9t request \u1ed5n \u0111\u1ecbnh c\u1ee7a \u1ee9ng d\u1ee5ng v\u00e0 \u0111\u1ecbnh danh c\u1ee7a l\u1eddi g\u1ecdi. L\u01b0u k\u1ebft qu\u1ea3 \u0111\u00e3 ho\u00e0n t\u1ea5t tr\u01b0\u1edbc khi tr\u1ea3 v\u1ec1 cho model. N\u1ebfu m\u1ed9t l\u1ea7n retry \u1edf t\u1ea7ng m\u1ea1ng g\u1eedi l\u1ea1i \u0111\u00fang l\u1eddi g\u1ecdi \u0111\u00f3, h\u00e3y tr\u1ea3 v\u1ec1 k\u1ebft qu\u1ea3 \u0111\u00e3 l\u01b0u thay v\u00ec ho\u00e0n ti\u1ec1n, g\u1eedi tin nh\u1eafn, deploy hay ghi database th\u00eam m\u1ed9t l\u1ea7n n\u1eefa.\n\nT\u00ean function v\u00e0 argument do model sinh ra l\u00e0 input kh\u00f4ng \u0111\u00e1ng tin c\u1eady. M\u1ed9t schema h\u1ee3p l\u1ec7 kh\u00f4ng c\u1ea5p quy\u1ec1n, kh\u00f4ng ch\u1ee9ng minh quy\u1ec1n s\u1edf h\u1eefu v\u00e0 kh\u00f4ng thay th\u1ebf \u0111\u01b0\u1ee3c ranh gi\u1edbi transaction.\n\n## Quy\u1ebft \u0111\u1ecbnh c\u00e1ch x\u1eed l\u00fd nhi\u1ec1u l\u1eddi g\u1ecdi\n\nC\u00e1c v\u00ed d\u1ee5 \u0111\u1eb7t `parallel_tool_calls: false` \u0111\u1ec3 state machine d\u1ec5 quan s\u00e1t. N\u1ebfu b\u1eadt l\u1eddi g\u1ecdi song song:\n\n- gh\u00e9p m\u1ecdi k\u1ebft qu\u1ea3 theo Call ID, kh\u00f4ng bao gi\u1edd theo th\u1ee9 t\u1ef1 ho\u00e0n t\u1ea5t;\n- \u0111\u1eb7t gi\u1edbi h\u1ea1n s\u1ed1 l\u1eddi g\u1ecdi t\u1ed1i \u0111a tr\u00ean m\u1ed7i response;\n- \u00e1p d\u1ee5ng gi\u1edbi h\u1ea1n concurrency trong \u1ee9ng d\u1ee5ng;\n- x\u00e1c \u0111\u1ecbnh khi m\u1ed9t tool l\u1ed7i th\u00ec s\u1ebd h\u1ee7y, ch\u1eb7n hay \u0111\u1ec3 nguy\u00ean c\u00e1c tool \u0111\u00e3 th\u00e0nh c\u00f4ng;\n- tr\u1ea3 v\u1ec1 \u0111\u00fang m\u1ed9t k\u1ebft qu\u1ea3 cho m\u1ed7i l\u1eddi g\u1ecdi \u0111\u00e3 ch\u1ea5p nh\u1eadn;\n- gi\u1eef c\u00e1c thao t\u00e1c c\u00f3 side effect ch\u1ea1y tu\u1ea7n t\u1ef1 khi th\u1ee9 t\u1ef1 l\u00e0 quan tr\u1ecdng.\n\nCh\u1ea1y song song c\u00f3 th\u1ec3 gi\u1ea3m latency cho c\u00e1c thao t\u00e1c \u0111\u1ecdc \u0111\u1ed9c l\u1eadp, nh\u01b0ng l\u00e0m t\u0103ng \u0111\u1ed9 ph\u1ee9c t\u1ea1p v\u1ec1 ph\u00e2n quy\u1ec1n, th\u1ee9 t\u1ef1, retry v\u00e0 l\u1ed7i m\u1ed9t ph\u1ea7n. H\u00e3y b\u1eadt n\u00f3 khi workload th\u1ef1c s\u1ef1 \u0111\u01b0\u1ee3c l\u1ee3i, ch\u1ee9 kh\u00f4ng ph\u1ea3i ch\u1ec9 v\u00ec tham s\u1ed1 \u0111\u00f3 t\u1ed3n t\u1ea1i.\n\n## Ranh gi\u1edbi t\u01b0\u01a1ng th\u00edch c\u1ee7a Modelflare\n\nL\u1edbp t\u01b0\u01a1ng th\u00edch OpenAI c\u1ee7a Modelflare gi\u1eef nguy\u00ean c\u00e1c \u0111\u1ecbnh ngh\u0129a function strict v\u00e0 chuy\u1ec3n \u0111\u1ed5i c\u00e1c d\u1ea1ng function call \u0111\u01b0\u1ee3c h\u1ed7 tr\u1ee3 gi\u1eefa Responses API v\u00e0 Chat Completions tr\u00ean c\u00e1c route OpenAI\/Codex \u0111\u1ee7 \u0111i\u1ec1u ki\u1ec7n. Ph\u1ea1m vi chuy\u1ec3n \u0111\u1ed5i n\u00e0y \u0111\u01b0\u1ee3c c\u1ed1 \u00fd gi\u1edbi h\u1ea1n h\u1eb9p h\u01a1n to\u00e0n b\u1ed9 t\u1eadp t\u00ednh n\u0103ng tool c\u1ee7a Responses API.\n\nFunction tool do \u1ee9ng d\u1ee5ng \u0111\u1ecbnh ngh\u0129a c\u00f3 th\u1ec3 bi\u1ec3u di\u1ec5n \u1edf c\u1ea3 hai \u0111\u1ecbnh d\u1ea1ng. C\u00f2n c\u00e1c hosted tool ch\u1ec9 c\u00f3 \u1edf Responses API \u2014 nh\u01b0 search do provider ch\u1ea1y, th\u1ef1c thi code hay c\u00e1c lo\u1ea1i tool built-in kh\u00e1c \u2014 kh\u00f4ng t\u01b0\u01a1ng \u0111\u01b0\u01a1ng v\u1edbi function calling c\u1ee7a \u1ee9ng d\u1ee5ng, v\u00e0 kh\u00f4ng th\u1ec3 m\u1eb7c \u0111\u1ecbnh l\u00e0 ch\u00fang s\u1ebd \u0111\u01b0\u1ee3c chuy\u1ec3n sang Chat Completions.\n\nC\u00e1c h\u1ecd model t\u01b0\u01a1ng th\u00edch OpenAI kh\u00e1c \u0111\u01b0\u1ee3c cung c\u1ea5p qua c\u01a1 ch\u1ebf pass-through Chat Completions nguy\u00ean b\u1ea3n, tr\u1eeb khi \u0111\u00e3 \u0111\u01b0\u1ee3c ki\u1ec3m ch\u1ee9ng ri\u00eang. V\u1edbi c\u00e1c route n\u00e0y, provider upstream quy\u1ebft \u0111\u1ecbnh vi\u1ec7c c\u00f3 h\u1ed7 tr\u1ee3 `tools`, `strict`, l\u1eddi g\u1ecdi song song, m\u1ea3nh argument khi streaming v\u00e0 c\u00e1c d\u1ea1ng `tool_choice` c\u1ee5 th\u1ec3 hay kh\u00f4ng.\n\nTr\u01b0\u1edbc khi b\u1eadt m\u1ed9t route, h\u00e3y ch\u1ea1y tr\u1ecdn v\u00f2ng l\u1eb7p thay v\u00ec ch\u1ec9 ki\u1ec3m tra request \u0111\u1ea7u ti\u00ean c\u00f3 tr\u1ea3 v\u1ec1 `200` hay kh\u00f4ng:\n\n| B\u00e0i test | B\u1eb1ng ch\u1ee9ng c\u1ea7n c\u00f3 |\n| --- | --- |\n| M\u1ed9t l\u1eddi g\u1ecdi ch\u1ec9 \u0111\u1ecdc | T\u00ean function, argument \u0111\u00e3 parse, Call ID, li\u00ean k\u1ebft k\u1ebft qu\u1ea3, text cu\u1ed1i c\u00f9ng |\n| Argument kh\u00f4ng h\u1ee3p l\u1ec7 | L\u1ed7i validate t\u01b0\u1eddng minh, tool kh\u00f4ng \u0111\u01b0\u1ee3c th\u1ef1c thi |\n| Function kh\u00f4ng x\u00e1c \u0111\u1ecbnh | B\u1ecb allowlist c\u1ee7a \u1ee9ng d\u1ee5ng t\u1eeb ch\u1ed1i |\n| Kh\u00f4ng c\u1ea7n tool | Text cu\u1ed1i c\u00f9ng b\u00ecnh th\u01b0\u1eddng, kh\u00f4ng c\u00f3 l\u1eddi g\u1ecdi b\u1ecba ra |\n| L\u1eddi g\u1ecdi d\u1ea1ng streaming | Argument \u0111\u01b0\u1ee3c gh\u00e9p l\u1ea1i \u0111\u1ea7y \u0111\u1ee7 v\u00e0 Call ID ch\u00ednh x\u00e1c |\n| Request l\u1eb7p l\u1ea1i | M\u1ed9t side effect ho\u1eb7c m\u1ed9t k\u1ebft qu\u1ea3 t\u1eeb cache, kh\u00f4ng th\u1ef1c thi tr\u00f9ng |\n| Nhi\u1ec1u l\u1eddi g\u1ecdi | Gh\u00e9p \u0111\u00fang, kh\u00f4ng ph\u1ee5 thu\u1ed9c th\u1ee9 t\u1ef1 ho\u00e0n t\u1ea5t |\n| Fallback route | Gi\u1eef nguy\u00ean model, giao th\u1ee9c, tool schema v\u00e0 contract k\u1ebft qu\u1ea3 |\n\nTham kh\u1ea3o [Reliable AI API Routing](https:\/\/modelflare.dev\/articles\/reliable-ai-api-routing) \u0111\u1ec3 qu\u1ea3n l\u00fd thay \u0111\u1ed5i route m\u1ed9t c\u00e1ch t\u01b0\u1eddng minh, v\u00e0 [AI API Key Security](https:\/\/modelflare.dev\/articles\/api-key-security-cost-controls) \u0111\u1ec3 t\u00e1ch bi\u1ec7t workload v\u00e0 quy\u1ec1n h\u1ea1n.\n\n## Ch\u1ecdn \u0111\u1ecbnh d\u1ea1ng theo contract c\u1ee7a \u1ee9ng d\u1ee5ng\n\nD\u00f9ng Responses API khi \u1ee9ng d\u1ee5ng \u0111\u01b0\u1ee3c l\u1ee3i t\u1eeb output item c\u00f3 ki\u1ec3u, m\u00f4 h\u00ecnh event c\u1ee7a Responses API, c\u00e1c t\u00f9y ch\u1ecdn ti\u1ebfp t\u1ee5c tr\u1ea1ng th\u00e1i ho\u1eb7c c\u00e1c t\u00ednh n\u0103ng Responses API kh\u00e1c \u0111\u00e3 \u0111\u01b0\u1ee3c ki\u1ec3m ch\u1ee9ng. D\u00f9ng Chat Completions khi \u1ee9ng d\u1ee5ng \u0111\u00e3 t\u1ef1 qu\u1ea3n l\u00fd m\u1ed9t l\u1ecbch s\u1eed message \u1ed5n \u0111\u1ecbnh v\u00e0 tool contract c\u1ee7a provider \u0111\u01b0\u1ee3c ch\u1ecdn \u0111\u00e3 \u0111\u01b0\u1ee3c ki\u1ec3m ch\u1ee9ng. B\u1ee9c tranh r\u1ed9ng h\u01a1n v\u1ec1 vi\u1ec7c ch\u1ecdn endpoint \u0111\u01b0\u1ee3c tr\u00ecnh b\u00e0y trong [Responses API vs Chat Completions](https:\/\/modelflare.dev\/articles\/responses-api-vs-chat-completions).\n\nD\u00f9 ch\u1ecdn b\u00ean n\u00e0o, ti\u00eau chu\u1ea9n c\u00e0i \u0111\u1eb7t v\u1eabn ph\u1ea3i gi\u1ed1ng nhau: allowlist tool t\u01b0\u1eddng minh, schema argument strict, validate ph\u00eda \u1ee9ng d\u1ee5ng, ph\u00e2n quy\u1ec1n tr\u01b0\u1edbc khi th\u1ef1c thi, gh\u00e9p theo Call ID, idempotency cho side effect v\u00e0 tr\u1ea3 k\u1ebft qu\u1ea3 \u0111\u1ea7y \u0111\u1ee7 v\u1ec1 cho model. Ch\u00ednh nh\u1eefng c\u01a1 ch\u1ebf ki\u1ec3m so\u00e1t n\u00e0y \u2014 ch\u1ee9 kh\u00f4ng ph\u1ea3i t\u00ean endpoint \u2014 m\u1edbi l\u00e0m cho m\u1ed9t workflow function calling tr\u1edf n\u00ean \u0111\u00e1ng tin c\u1eady.\n\n---\n\nT\u00e1c gi\u1ea3 l\u00e0 \u0111\u1ed9i ng\u0169 ph\u00e1t tri\u1ec3n Modelflare, m\u1ed9t AI API gateway; n\u1ebfu b\u1ea1n mu\u1ed1n d\u00f9ng nhi\u1ec1u provider qua m\u1ed9t API t\u01b0\u01a1ng th\u00edch OpenAI, c\u00f3 th\u1ec3 tham kh\u1ea3o th\u00eam t\u1ea1i [https:\/\/modelflare.dev](https:\/\/modelflare.dev\/?utm_source=viblo&utm_medium=syndication&utm_campaign=blog).","published_at":"2026-10-25T10:58:16.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T13:00:14.000000Z","edited_at":"2026-10-25T10:57:50.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":11,"points":0,"views_count":6,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/4fd0447e-f578-4211-8ac6-aeec52170a07.png","user":{"data":{"id":226961,"url":"https:\/\/viblo.asia\/u\/castaly","avatar":null,"name":"Castaly","username":"castaly","followers_count":0,"reputation":0,"posts_count":0,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"ai","name":"AI"},{"slug":"api","name":"API"},{"slug":"function-calling","name":"function calling"},{"slug":"llm","name":"LLM"},{"slug":"openai","name":"OpenAI"}]},"commentators":{"data":[]}},{"id":109668,"title":"Ch\u1ecdn model t\u1ea1o video AI theo \"gi\u00e1 m\u1ed7i gi\u00e2y \u00d7 \u0111\u1ed9 ph\u00e2n gi\u1ea3i \u00d7 th\u1eddi l\u01b0\u1ee3ng\": b\u1ea3ng gi\u00e1 Kling \/ Wan \/ MiniMax v\u00e0 v\u00ed d\u1ee5 g\u1ecdi API b\u1eb1ng curl","slug":"QyJKzWQM4Me","url":"https:\/\/viblo.asia\/p\/chon-model-tao-video-ai-theo-gia-moi-giay-do-phan-giai-thoi-luong-bang-gia-kling-wan-minimax-va-vi-du-goi-api-bang-curl-QyJKzWQM4Me","user_id":226961,"moderation":"pending","transliterated":"chon-model-tao-video-ai-theo-gia-moi-giay-do-phan-giai-thoi-luong-bang-gia-kling-wan-minimax-va-vi-du-goi-api-bang-curl","contents_short":"M\u1edf \u0111\u1ea7u\n\nPh\u1ea7n l\u1edbn model t\u1ea1o video hi\u1ec7n nay t\u00ednh ti\u1ec1n theo gi\u00e2y, v\u00e0 \u0111\u01a1n gi\u00e1 ph\u1ee5 thu\u1ed9c v\u00e0o \u0111\u1ed9 ph\u00e2n gi\u1ea3i. C\u00f9ng m\u1ed9t model, ch\u00eanh l\u1ec7ch gi\u1eefa 720p v\u00e0 1080p \u0111\u00e3 \u0111\u00e1ng k\u1ec3; nh\u00e2n th\u00eam v\u1edbi th\u1eddi l\u01b0\u1ee3ng v\u00e0 s\u1ed1 l\u1ea7n th\u1eed th\u00ec kho\u1ea3ng c\u00e1ch c\u00f2n l\u1edbn h\u01a1n.\nB\u00e0i n\u00e0y t\u1ed5ng h\u1ee3p ba th\u1ee9: \u0111\u01a1n gi\u00e1 m\u1ed7i gi\u00e2y c\u1ee7a c\u00e1c model, c\u00e1ch ch\u1ecdn model theo y\u00eau c\u1ea7u c\u1ee7a t\u1eebng c\u1ea3nh quay, v\u00e0 quy tr\u00ecnh t\u1ea1o video qua API.\n\nC\u00f4ng khai: m\u00ecnh l\u00e0 Magnus, ng\u01b0...","contents":"## M\u1edf \u0111\u1ea7u\n\nPh\u1ea7n l\u1edbn model t\u1ea1o video hi\u1ec7n nay t\u00ednh ti\u1ec1n **theo gi\u00e2y, v\u00e0 \u0111\u01a1n gi\u00e1 ph\u1ee5 thu\u1ed9c v\u00e0o \u0111\u1ed9 ph\u00e2n gi\u1ea3i**. C\u00f9ng m\u1ed9t model, ch\u00eanh l\u1ec7ch gi\u1eefa 720p v\u00e0 1080p \u0111\u00e3 \u0111\u00e1ng k\u1ec3; nh\u00e2n th\u00eam v\u1edbi th\u1eddi l\u01b0\u1ee3ng v\u00e0 s\u1ed1 l\u1ea7n th\u1eed th\u00ec kho\u1ea3ng c\u00e1ch c\u00f2n l\u1edbn h\u01a1n.\nB\u00e0i n\u00e0y t\u1ed5ng h\u1ee3p ba th\u1ee9: \u0111\u01a1n gi\u00e1 m\u1ed7i gi\u00e2y c\u1ee7a c\u00e1c model, c\u00e1ch ch\u1ecdn model theo y\u00eau c\u1ea7u c\u1ee7a t\u1eebng c\u1ea3nh quay, v\u00e0 quy tr\u00ecnh t\u1ea1o video qua API.\n\n> C\u00f4ng khai: m\u00ecnh l\u00e0 Magnus, ng\u01b0\u1eddi \u0111ang x\u00e2y d\u1ef1ng Castaly (Modelflare), m\u1ed9t studio \u0111\u1ec3 so s\u00e1nh v\u00e0 d\u00f9ng nhi\u1ec1u model t\u1ea1o video\/\u1ea3nh.\n> \u0110\u01a1n gi\u00e1 b\u00ean d\u01b0\u1edbi l\u00e0 gi\u00e1 c\u00f4ng khai tr\u00ean trang gi\u00e1 c\u1ee7a Castaly ng\u00e0y 25\/10\/2026, kh\u00e1c v\u1edbi gi\u00e1 ch\u00ednh th\u1ee9c c\u1ee7a t\u1eebng nh\u00e0 cung c\u1ea5p model.\n\n## 1. B\u1ea3ng \u0111\u01a1n gi\u00e1 m\u1ed7i gi\u00e2y (USD)\n\n| Model | \u0110\u1ed9 ph\u00e2n gi\u1ea3i | M\u1ed7i gi\u00e2y | 5 gi\u00e2y | Th\u1eddi l\u01b0\u1ee3ng |\n|---|---|---|---|---|\n| Kling 2.6 | 720p | 0.0382 | \u2248 0.19 | 5 \/ 10 gi\u00e2y |\n| Kling 2.6 | 1080p | 0.0637 | \u2248 0.32 | 5 \/ 10 gi\u00e2y |\n| Kling 3.0 | 720p | 0.0764 | \u2248 0.38 | 3\u201315 gi\u00e2y |\n| Kling 3.0 | 1080p | 0.1019 | \u2248 0.51 | 3\u201315 gi\u00e2y |\n| Kling 3.0 | 1080p (c\u00f3 \u00e2m thanh) | 0.1529 | \u2248 0.76 | 3\u201315 gi\u00e2y |\n| Kling 3.0 | 4K | 0.3822 | \u2248 1.91 | 3\u201315 gi\u00e2y |\n| Wan 2.7 | 720p | 0.0741 | \u2248 0.37 | 2\u201315 gi\u00e2y |\n| Wan 2.7 | 1080p | 0.1112 | \u2248 0.56 | 2\u201315 gi\u00e2y |\n| MiniMax H3 | 768p | 0.0936 | \u2248 0.47 | 4\u201315 gi\u00e2y |\n| MiniMax H3 | 2K | 0.1521 | \u2248 0.76 | 4\u201315 gi\u00e2y |\n\nSeedance v\u00e0 GPT Image t\u00ednh theo token n\u00ean gi\u00e1 thay \u0111\u1ed5i theo c\u1ea5u h\u00ecnh, kh\u00f4ng \u0111\u01b0a v\u00e0o b\u1ea3ng. V\u1edbi \u1ea3nh, Wan 2.7 Image kho\u1ea3ng $0.021 m\u1ed7i \u1ea3nh.\n\n## 2. \u0110\u1ecdc b\u1ea3ng gi\u00e1\n\n1. **T\u0103ng m\u1ed9t b\u1eadc \u0111\u1ed9 ph\u00e2n gi\u1ea3i, \u0111\u01a1n gi\u00e1 t\u0103ng kho\u1ea3ng 1,3\u20132 l\u1ea7n.** Kling 3.0 t\u1eeb 720p l\u00ean 1080p \u2248 1,33 l\u1ea7n, Kling 2.6 \u2248 1,67 l\u1ea7n, Wan 2.7 \u2248 1,5 l\u1ea7n; 4K c\u1ee7a Kling 3.0 \u2248 3,75 l\u1ea7n so v\u1edbi 1080p.\n2. **T\u00ednh theo gi\u00e2y, n\u00ean th\u1eddi l\u01b0\u1ee3ng ch\u00ednh l\u00e0 chi ph\u00ed.** Kling 3.0 1080p: 5 gi\u00e2y \u2248 $0.51, 10 gi\u00e2y \u2248 $1.02, 15 gi\u00e2y \u2248 $1.53.\n3. **C\u00f3 \u00e2m thanh th\u00ec \u0111\u01a1n gi\u00e1 kh\u00e1c.** Kling 3.0 1080p c\u00f3 \u00e2m thanh t\u0103ng t\u1eeb $0.1019\/gi\u00e2y l\u00ean $0.1529\/gi\u00e2y.\n4. **T\u00e1ch model cho b\u1ea3n nh\u00e1p v\u00e0 b\u1ea3n cu\u1ed1i c\u00f3 th\u1ec3 gi\u1ea3m h\u01a1n m\u1ed9t n\u1eeda t\u1ed5ng chi ph\u00ed** (10 l\u1ea7n t\u1ea1o clip 5 gi\u00e2y):\n   - C\u1ea3 10 l\u1ea7n d\u00f9ng Kling 3.0 1080p: 0.5096 \u00d7 10 \u2248 $5.10\n   - 9 l\u1ea7n nh\u00e1p b\u1eb1ng Kling 2.6 720p, l\u1ea7n cu\u1ed1i b\u1eb1ng Kling 3.0 1080p: 0.1911 \u00d7 9 + 0.5096 \u2248 $2.23\n\n   L\u01b0u \u00fd: m\u1ed7i model ph\u1ea3n \u1ee9ng v\u1edbi prompt theo m\u1ed9t ki\u1ec3u kh\u00e1c, n\u00ean h\u00e3y ch\u1eeba v\u00e0i l\u1ea7n ch\u1ec9nh tr\u00ean model cu\u1ed1i.\n\n## 3. Ch\u1ecdn model theo y\u00eau c\u1ea7u c\u1ea3nh quay (ch\u1ec9 d\u1ef1a v\u00e0o th\u00f4ng s\u1ed1)\n\n| Y\u00eau c\u1ea7u | \u1ee8ng vi\u00ean | L\u00fd do |\n|---|---|---|\n| Th\u1eed b\u1ed1 c\u1ee5c, chuy\u1ec3n \u0111\u1ed9ng camera (5 gi\u00e2y l\u00e0 \u0111\u1ee7) | Kling 2.6 720p | \u0110\u01a1n gi\u00e1 th\u1ea5p nh\u1ea5t trong b\u1ea3ng ($0.0382\/gi\u00e2y) |\n| C\u1ea3nh d\u00e0i h\u01a1n 15 gi\u00e2y | Seedance 2.5 | T\u1ed1i \u0111a 30 gi\u00e2y |\n| C\u1ea7n l\u1eddi tho\u1ea1i, hi\u1ec7u \u1ee9ng \u00e2m thanh | Kling 2.6\/3.0 (c\u00f3 \u00e2m thanh), Seedance | H\u1ed7 tr\u1ee3 t\u1ea1o \u00e2m thanh; MiniMax H3 v\u00e0 Wan 2.7 th\u00ec kh\u00f4ng |\n| Khung 21:9 | MiniMax H3, Seedance | H\u1ed7 tr\u1ee3 21:9 |\n| Khung 4:3 \/ 3:4 | Wan 2.7, MiniMax H3, Seedance | Kling ch\u1ec9 c\u00f3 16:9 \/ 9:16 \/ 1:1 |\n| Giao b\u1ea3n 4K | Kling 3.0 4K, Seedance 2.0 | C\u00f3 t\u00f9y ch\u1ecdn 4K |\n| C\u1ed1 \u0111\u1ecbnh khung \u0111\u1ea7u\/cu\u1ed1i \u0111\u1ec3 n\u1ed1i c\u1ea3nh | Kling, MiniMax H3, Seedance | H\u1ed7 tr\u1ee3 first_frame \/ last_frame |\n| Nhi\u1ec1u t\u01b0 li\u1ec7u tham chi\u1ebfu | Seedance 2.5 (t\u1ed1i \u0111a 50), MiniMax H3 (t\u1ed1i \u0111a 12) | Kling 2.6\/3.0 t\u1ed1i \u0111a 2 |\n\n**C\u00e1c b\u01b0\u1edbc ch\u1ecdn**\n1. Ch\u1ed1t \u0111\u1ed9 ph\u00e2n gi\u1ea3i, t\u1ec9 l\u1ec7 khung h\u00ecnh, th\u1eddi l\u01b0\u1ee3ng v\u00e0 nhu c\u1ea7u \u00e2m thanh c\u1ee7a s\u1ea3n ph\u1ea9m cu\u1ed1i\n2. L\u1ecdc model th\u1ecfa \u0111i\u1ec1u ki\u1ec7n b\u1eb1ng b\u1ea3ng tr\u00ean\n3. Ch\u1ecdn model\/\u0111\u1ed9 ph\u00e2n gi\u1ea3i cho b\u1ea3n nh\u00e1p (gi\u00e1 th\u1ea5p) v\u00e0 cho b\u1ea3n cu\u1ed1i\n4. \u01af\u1edbc t\u00ednh t\u1ed5ng chi ph\u00ed: `\u0111\u01a1n gi\u00e1 m\u1ed7i gi\u00e2y \u00d7 th\u1eddi l\u01b0\u1ee3ng \u00d7 s\u1ed1 l\u1ea7n th\u1eed`\n\n## 4. T\u1ea1o video qua API: t\u1ea1o task \u2192 polling \u2192 t\u1ea3i v\u1ec1\n\nC\u00e1c model tr\u00ean Castaly c\u0169ng c\u00f3 th\u1ec3 g\u1ecdi qua API c\u1ee7a Modelflare v\u1edbi c\u00f9ng m\u1ee9c gi\u00e1 c\u00f4ng khai. Video l\u00e0 task b\u1ea5t \u0111\u1ed3ng b\u1ed9:\n\n| Thao t\u00e1c | Endpoint |\n|---|---|\n| T\u1ea1o task | `POST https:\/\/modelflare.dev\/v1\/videos` |\n| Ki\u1ec3m tra tr\u1ea1ng th\u00e1i | `GET https:\/\/modelflare.dev\/v1\/videos\/{task_id}` |\n| T\u1ea3i video | `GET https:\/\/modelflare.dev\/v1\/videos\/{task_id}\/content` |\n\nBody c\u1ee7a request kh\u00e1c nhau theo h\u1ecd model. V\u00ed d\u1ee5 v\u1edbi Kling 2.6 (`mode: \"std\"` = 720p, `\"pro\"` = 1080p; `duration` l\u00e0 chu\u1ed7i `\"5\"` ho\u1eb7c `\"10\"`):\n\n```bash\nexport MODELFLARE_API_KEY=\"...\"   # t\u1ea1o t\u1ea1i https:\/\/modelflare.dev\/keys\n\n# 1. T\u1ea1o task v\u00e0 l\u1ea5y ID\nTASK_ID=$(curl -s https:\/\/modelflare.dev\/v1\/videos \\\n  -H \"Authorization: Bearer $MODELFLARE_API_KEY\" \\\n  -H \"Content-Type: application\/json\" \\\n  -d '{\n    \"model_name\": \"kling-2.6\",\n    \"prompt\": \"A white cat runs through a neon-lit street in the rain, cinematic tracking shot\",\n    \"duration\": \"5\",\n    \"mode\": \"std\"\n  }' | jq -r '.id \/\/ .task_id')\n\n# 2. Polling \u0111\u1ebfn khi completed \/ failed (queued \u2192 in_progress \u2192 completed \/ failed)\nwhile true; do\n  STATUS=$(curl -s \"https:\/\/modelflare.dev\/v1\/videos\/$TASK_ID\" \\\n    -H \"Authorization: Bearer $MODELFLARE_API_KEY\" | jq -r '.status')\n  echo \"status: $STATUS\"\n  case \"$STATUS\" in\n    completed) break ;;\n    failed) echo \"generation failed\"; exit 1 ;;\n  esac\n  sleep 10\ndone\n\n# 3. T\u1ea3i v\u1ec1 (URL k\u1ebft qu\u1ea3 c\u00f3 th\u1ec3 h\u1ebft h\u1ea1n, n\u00ean l\u01b0u ngay khi xong)\ncurl -s -L \"https:\/\/modelflare.dev\/v1\/videos\/$TASK_ID\/content\" \\\n  -H \"Authorization: Bearer $MODELFLARE_API_KEY\" -o kling26_720p_5s.mp4\n```\n\nChi ph\u00ed c\u1ee7a v\u00ed d\u1ee5 n\u00e0y (Kling 2.6 \/ 720p \/ 5 gi\u00e2y): 0.0382 \u00d7 5 \u2248 **$0.19**.\nL\u1ed7i th\u01b0\u1eddng g\u1eb7p: `401` (sai key), `403` k\u00e8m `insufficient_user_quota` (kh\u00f4ng \u0111\u1ee7 s\u1ed1 d\u01b0), `429` (rate limit, xem header `Retry-After`). \u0110\u1ecbnh d\u1ea1ng request c\u1ee7a c\u00e1c model kh\u00e1c c\u00f3 trong t\u00e0i li\u1ec7u t\u1ea1i docs.modelflare.dev.\n\n## 5. Checklist\n\n- \u0110\u00e3 ch\u1ed1t \u0111\u1ed9 ph\u00e2n gi\u1ea3i, t\u1ec9 l\u1ec7, th\u1eddi l\u01b0\u1ee3ng, \u00e2m thanh c\u1ee7a b\u1ea3n cu\u1ed1i ch\u01b0a?\n- \u0110\u00e3 t\u00e1ch model cho b\u1ea3n nh\u00e1p v\u00e0 b\u1ea3n cu\u1ed1i ch\u01b0a?\n- \u0110ang so s\u00e1nh \"t\u1ed5ng chi ph\u00ed \u0111\u1ebfn khi xong\" ch\u1ee9 kh\u00f4ng ph\u1ea3i \"gi\u00e1 m\u1ed9t clip\"?\n\n## K\u1ebft\n\nB\u1ea3ng gi\u00e1 trong b\u00e0i l\u1ea5y t\u1eeb Castaly, s\u1ea3n ph\u1ea9m m\u00ecnh \u0111ang x\u00e2y d\u1ef1ng. Tr\u00ean Castaly b\u1ea1n so s\u00e1nh c\u00e1c model (Kling 2.6 v\u00e0 3.0, Wan 2.7, MiniMax, Seedance, GPT Image) theo th\u00f4ng s\u1ed1 v\u00e0 gi\u00e1, r\u1ed3i t\u1ea1o t\u1eebng clip m\u1ed9t, gi\u00e1 hi\u1ec3n th\u1ecb tr\u01b0\u1edbc khi t\u1ea1o.\n\n- Tr\u1ea3 ti\u1ec1n theo m\u1ed7i l\u1ea7n t\u1ea1o: kh\u00f4ng c\u00f3 g\u00f3i thu\u00ea bao, kh\u00f4ng c\u00f3 credit mi\u1ec5n ph\u00ed\n- Xem gallery c\u1ed9ng \u0111\u1ed3ng kh\u00f4ng c\u1ea7n \u0111\u0103ng k\u00fd; mu\u1ed1n remix m\u1ed9t t\u00e1c ph\u1ea9m th\u00ec c\u1ea7n t\u00e0i kho\u1ea3n\n- Giao di\u1ec7n hi\u1ec7n ch\u1ec9 c\u00f3 ti\u1ebfng Anh v\u00e0 ti\u1ebfng Trung (ch\u01b0a c\u00f3 ti\u1ebfng Vi\u1ec7t)\n\nhttps:\/\/castaly.modelflare.dev\/?utm_source=viblo&utm_medium=article&utm_campaign=launch","published_at":"2026-10-25T10:43:31.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T10:44:02.000000Z","edited_at":"2026-10-25T10:43:05.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":4,"points":0,"views_count":1,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/26d95a15-7d6e-46a1-8dc4-de12729d0e1e.png","user":{"data":{"id":226961,"url":"https:\/\/viblo.asia\/u\/castaly","avatar":null,"name":"Castaly","username":"castaly","followers_count":0,"reputation":0,"posts_count":0,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"ai","name":"AI"},{"slug":"api","name":"API"},{"slug":"kling","name":"kling"},{"slug":"video-generation","name":"Video Generation"},{"slug":"cost-optimization","name":"Cost Optimization"}]},"commentators":{"data":[]}},{"id":109667,"title":"AE888 - S\u00e2n Ch\u01a1i S\u00f4i \u0110\u1ed9ng, C\u01a1 H\u1ed9i Ng\u1eadp Tr\u00e0n","slug":"2vJPd0RKJeK","url":"https:\/\/viblo.asia\/p\/ae888-san-choi-soi-dong-co-hoi-ngap-tran-2vJPd0RKJeK","user_id":226952,"moderation":"discarded","transliterated":"ae888-san-choi-soi-dong-co-hoi-ngap-tran","contents_short":"AE888 l\u00e0 trang ch\u1ee7 c\u1eadp nh\u1eadt link v\u00e0o m\u1edbi nh\u1ea5t kh\u00f4ng b\u1ecb ch\u1eb7n. T\u1ea3i app AE888 m\u01b0\u1ee3t m\u00e0 cho iOS\/Android \u0111\u1ec3 tr\u1ea3i nghi\u1ec7m th\u1ebf gi\u1edbi c\u00e1 c\u01b0\u1ee3c \u0111\u1ec9nh cao ngay h\u00f4m nay!.\nhttps:\/\/mega38shope.com\/\nmega38shope@gmail.com\n0928117283\n\u0110\u01b0\u1eddng Phan B\u1ed9i Ch\u00e2u, khu v\u1ef1c Vinh, t\u1ec9nh Ngh\u1ec7 An.\n#ae888 #trangchuae888 #casinoae888 #dagaae888\nhttps:\/\/x.com\/ae888shope\nhttps:\/\/www.youtube.com\/@ae888shope\nhttps:\/\/www.pinterest.com\/ae...","contents":"AE888 l\u00e0 trang ch\u1ee7 c\u1eadp nh\u1eadt link v\u00e0o m\u1edbi nh\u1ea5t kh\u00f4ng b\u1ecb ch\u1eb7n. T\u1ea3i app AE888 m\u01b0\u1ee3t m\u00e0 cho iOS\/Android \u0111\u1ec3 tr\u1ea3i nghi\u1ec7m th\u1ebf gi\u1edbi c\u00e1 c\u01b0\u1ee3c \u0111\u1ec9nh cao ngay h\u00f4m nay!. \nhttps:\/\/mega38shope.com\/\nmega38shope@gmail.com\n0928117283\n\u0110\u01b0\u1eddng Phan B\u1ed9i Ch\u00e2u, khu v\u1ef1c Vinh, t\u1ec9nh Ngh\u1ec7 An.\n#ae888 #trangchuae888 #casinoae888 #dagaae888\nhttps:\/\/x.com\/ae888shope\nhttps:\/\/www.youtube.com\/@ae888shope\nhttps:\/\/www.pinterest.com\/ae888shope\/_profile\/\nhttps:\/\/medium.com\/@ae888shope\/about\nhttps:\/\/fr.quora.com\/profile\/AE888-SHOPE\nhttps:\/\/gravatar.com\/ae888shope\nhttps:\/\/profile.hatena.ne.jp\/ae888shope\/profile\nhttps:\/\/www.mixcloud.com\/ae888shope\/\nhttps:\/\/about.me\/ae888shope\/","published_at":"2026-10-25T10:27:46.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T10:28:02.000000Z","edited_at":"2026-10-25T10:27:21.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":0,"points":0,"views_count":1,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/09c247de-0842-40db-b700-40133a38af45.png","user":{"data":{"id":226952,"url":"https:\/\/viblo.asia\/u\/ae888shope","avatar":"15455dec-2a6d-4398-aa0d-2b1fc5fc3e8b.jpg","name":"AESHOPE","username":"ae888shope","followers_count":0,"reputation":0,"posts_count":0,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"ae888n","name":"AE888N"}]},"commentators":{"data":[]}},{"id":109618,"title":"Microsoft Word - B\u00e0i 1: Giao di\u1ec7n Microsoft Word: Hi\u1ec3u \u0111\u00fang thanh Ribbon, Quick Access v\u00e0 Status Bar","slug":"7Z4DEWa2JnX","url":"https:\/\/viblo.asia\/p\/microsoft-word-bai-1-giao-dien-microsoft-word-hieu-dung-thanh-ribbon-quick-access-va-status-bar-7Z4DEWa2JnX","user_id":182732,"moderation":null,"transliterated":"microsoft-word-bai-1-giao-dien-microsoft-word-hieu-dung-thanh-ribbon-quick-access-va-status-bar","contents_short":"\u0110\u1ec3 ng\u01b0\u1eddi h\u1ecdc kh\u00f4ng b\u1ecb ng\u1ee3p tr\u01b0\u1edbc h\u00e0ng tr\u0103m n\u00fat b\u1ea5m khi m\u1edbi m\u1edf ph\u1ea7n m\u1ec1m, b\u00e0i h\u1ecdc \u0111\u1ea7u ti\u00ean s\u1ebd t\u1eadp trung v\u00e0o vi\u1ec7c \"\u0111\u1ecbnh v\u1ecb b\u1ea3n \u0111\u1ed3\" tr\u00ean m\u00e0n h\u00ecnh l\u00e0m vi\u1ec7c v\u00e0 x\u1eed l\u00fd ngay c\u00e1c l\u1ed7i hi\u1ec3n th\u1ecb giao di\u1ec7n hay g\u1eb7p nh\u1ea5t.\n\n1. M\u1ee5c ti\u00eau b\u00e0i h\u1ecdc (Sau b\u00e0i n\u00e0y ng\u01b0\u1eddi h\u1ecdc l\u00e0m \u0111\u01b0\u1ee3c g\u00ec?)\n\n-   N\u1eafm v\u1eefng v\u1ecb tr\u00ed v\u00e0 ch\u1ee9c n\u0103ng c\u1ee7a 3 khu v\u1ef1c \u0111i\u1ec1u khi\u1ec3n quan tr\u1ecdng nh\u1ea5t:  Ribbon,  Quick Access Toolbar, v\u00e0 Status Bar.\n\n-   Bi\u1ebft ...","contents":"\u0110\u1ec3 ng\u01b0\u1eddi h\u1ecdc kh\u00f4ng b\u1ecb ng\u1ee3p tr\u01b0\u1edbc h\u00e0ng tr\u0103m n\u00fat b\u1ea5m khi m\u1edbi m\u1edf ph\u1ea7n m\u1ec1m, b\u00e0i h\u1ecdc \u0111\u1ea7u ti\u00ean s\u1ebd t\u1eadp trung v\u00e0o vi\u1ec7c \"\u0111\u1ecbnh v\u1ecb b\u1ea3n \u0111\u1ed3\" tr\u00ean m\u00e0n h\u00ecnh l\u00e0m vi\u1ec7c v\u00e0 x\u1eed l\u00fd ngay c\u00e1c l\u1ed7i hi\u1ec3n th\u1ecb giao di\u1ec7n hay g\u1eb7p nh\u1ea5t.\n\n### 1. M\u1ee5c ti\u00eau b\u00e0i h\u1ecdc (Sau b\u00e0i n\u00e0y ng\u01b0\u1eddi h\u1ecdc l\u00e0m \u0111\u01b0\u1ee3c g\u00ec?)\n\n-   N\u1eafm v\u1eefng v\u1ecb tr\u00ed v\u00e0 ch\u1ee9c n\u0103ng c\u1ee7a 3 khu v\u1ef1c \u0111i\u1ec1u khi\u1ec3n quan tr\u1ecdng nh\u1ea5t:  **Ribbon**,  **Quick Access Toolbar**, v\u00e0 **Status Bar**.\n    \n-   Bi\u1ebft c\u00e1ch t\u1ef1 kh\u00f4i ph\u1ee5c l\u1ea1i thanh c\u00f4ng c\u1ee5 khi l\u1ee1 tay b\u1ea5m \u1ea9n m\u1ea5t (l\u1ed7i 90% ng\u01b0\u1eddi m\u1edbi \u0111\u1ec1u g\u1eb7p).\n    \n-   Bi\u1ebft c\u00e1ch \u0111\u01b0a c\u00e1c n\u00fat l\u1ec7nh hay d\u00f9ng ra ngo\u00e0i c\u00f9ng \u0111\u1ec3 thao t\u00e1c nhanh g\u1ea5p \u0111\u00f4i.\n    \n\n### 2. N\u1ed9i dung chi ti\u1ebft & K\u1ecbch b\u1ea3n h\u01b0\u1edbng d\u1eabn (T\u1eebng b\u01b0\u1edbc)\n\n#### Ph\u1ea7n A: Thanh Ribbon \u2013 \"Trung t\u00e2m \u0111i\u1ec1u khi\u1ec3n\" c\u1ee7a Word\n\n![image.png](https:\/\/images.viblo.asia\/6638e425-ffd2-4296-9b85-70da3b66698f.png)\n\n-   **Kh\u00e1i ni\u1ec7m d\u1ec5 hi\u1ec3u:** H\u00e3y v\u00ed thanh Ribbon gi\u1ed1ng nh\u01b0 m\u1ed9t chi\u1ebfc t\u1ee7 \u0111\u1ef1ng \u0111\u1ed3 ngh\u1ec1 \u0111\u01b0\u1ee3c chia th\u00e0nh nhi\u1ec1u ng\u0103n.\n    \n-   **C\u1ea5u tr\u00fac 3 c\u1ea5p \u0111\u1ed9 c\u1ea7n ch\u1ec9 r\u00f5 tr\u00ean m\u00e0n h\u00ecnh:**\n    \n    1.  **Tabs (C\u00e1c th\u1ebb):** N\u1eb1m \u1edf h\u00e0ng ngang tr\u00ean c\u00f9ng (_Home, Insert, Layout, References..._). M\u1ed7i th\u1ebb ph\u1ee5c v\u1ee5 m\u1ed9t m\u1ee5c \u0111\u00edch ri\u00eang (Home \u0111\u1ec3 ch\u1ec9nh ch\u1eef, Insert \u0111\u1ec3 ch\u00e8n b\u1ea3ng\/\u1ea3nh, Layout \u0111\u1ec3 c\u0103n l\u1ec1...).\n\n![image.png](https:\/\/images.viblo.asia\/8f65741a-5acd-4c30-b69f-6714a2ed10f3.png)\n\n        \n   2.  **Groups (C\u00e1c nh\u00f3m l\u1ec7nh):** Trong m\u1ed7i th\u1ebb s\u1ebd chia nh\u1ecf th\u00e0nh c\u00e1c c\u1ee5m c\u00f3 v\u1ea1ch k\u1ebb ng\u0103n c\u00e1ch (V\u00ed d\u1ee5 trong th\u1ebb _Home_ c\u00f3 c\u1ee5m _Font_, c\u1ee5m _Paragraph_, c\u1ee5m _Styles_).\n  \n  ![image.png](https:\/\/images.viblo.asia\/9bfc283b-9ebf-49bb-ad77-3a7d7ef2e6e1.png)\n  \n   3.  **Dialog Box Launcher (M\u0169i t\u00ean nh\u1ecf \u1edf g\u00f3c d\u01b0\u1edbi b\u00ean ph\u1ea3i m\u1ed7i Group):** \u0110\u00e2y l\u00e0 \"c\u0103n ph\u00f2ng b\u00ed m\u1eadt\". Nh\u1eefng c\u00e0i \u0111\u1eb7t chuy\u00ean s\u00e2u nh\u1ea5t \u0111\u1ec1u n\u1eb1m trong n\u00fat m\u0169i t\u00ean nh\u1ecf x\u00edu n\u00e0y.\n\n![image.png](https:\/\/images.viblo.asia\/bf6e1639-127b-4eb5-9b6f-27495e74e0e0.png)\n        \n-   **M\u1eb9o th\u1ef1c chi\u1ebfn (\u0110i\u1ec3m \u0103n ti\u1ec1n c\u1ee7a video):**\n    \n    -   _T\u00ecnh hu\u1ed1ng:_ \u0110ang l\u00e0m vi\u1ec7c t\u1ef1 nhi\u00ean thanh c\u00f4ng c\u1ee5 bi\u1ebfn m\u1ea5t, ch\u1ec9 c\u00f2n m\u1ed7i trang gi\u1ea5y tr\u1eafng.\n        \n    -   _C\u00e1ch x\u1eed l\u00fd:_ Nh\u1ea5n t\u1ed5 h\u1ee3p ph\u00edm **`Ctrl + F1`** (ho\u1eb7c b\u1ea5m v\u00e0o bi\u1ec3u t\u01b0\u1ee3ng m\u0169i t\u00ean nh\u1ecf\/h\u00ecnh chi\u1ebfc ghim \u1edf g\u00f3c ph\u1ea3i thanh Ribbon) \u0111\u1ec3 b\u1eadt\/t\u1eaft c\u1ed1 \u0111\u1ecbnh thanh c\u00f4ng c\u1ee5.\n        \n        \n   ![image.png](https:\/\/images.viblo.asia\/f01934ca-d2a1-416d-a82a-1317535eab7c.png)\n\n#### Ph\u1ea7n B: Quick Access Toolbar \u2013 \"Thanh c\u00f4ng c\u1ee5 truy c\u1eadp nhanh\"\n\n-   **V\u1ecb tr\u00ed:** N\u1eb1m \u1edf g\u00f3c tr\u00ean c\u00f9ng b\u00ean tr\u00e1i m\u00e0n h\u00ecnh (M\u1eb7c \u0111\u1ecbnh th\u01b0\u1eddng c\u00f3 n\u00fat _Save_ h\u00ecnh \u0111\u0129a m\u1ec1m,  _Undo_ quay l\u1ea1i,  _Redo_ ti\u1ebfn t\u1edbi).\n\n![image.png](https:\/\/images.viblo.asia\/c9888871-764b-433d-b1e6-eca7a6dfb3f4.png)\n    \n-   **T\u1ea1i sao ph\u1ea3i d\u00f9ng?** D\u00f9 b\u1ea1n \u0111ang \u1edf b\u1ea5t k\u1ef3 th\u1ebb n\u00e0o tr\u00ean thanh Ribbon, c\u00e1c n\u00fat tr\u00ean thanh Quick Access v\u1eabn lu\u00f4n \u0111\u1ee9ng im m\u1ed9t ch\u1ed7 \u0111\u1ec3 b\u1ea1n b\u1ea5m ngay l\u1eadp t\u1ee9c.\n    \n-   **Thao t\u00e1c h\u01b0\u1edbng d\u1eabn th\u1ef1c h\u00e0nh:**\n    \n    1.  B\u1ea5m v\u00e0o m\u0169i t\u00ean tr\u1ecf xu\u1ed1ng \u1edf cu\u1ed1i thanh **Quick Access Toolbar** -> T\u00edch ch\u1ecdn th\u00eam **New**,  **Open**,  **Print Preview and Print**.\n        \n    2.  **M\u1eb9o n\u00e2ng cao:** Th\u1ea5y n\u00fat n\u00e0o tr\u00ean thanh Ribbon hay ph\u1ea3i d\u00f9ng (v\u00ed d\u1ee5: n\u00fat _Insert Table_ ho\u1eb7c n\u00fat _Clear All Formatting_), ch\u1ec9 c\u1ea7n **Click chu\u1ed9t ph\u1ea3i v\u00e0o n\u00fat \u0111\u00f3 -> Ch\u1ecdn \"Add to Quick Access Toolbar\"**. N\u00fat \u0111\u00f3 s\u1ebd l\u1eadp t\u1ee9c nh\u1ea3y l\u00ean g\u00f3c tr\u00ean c\u00f9ng.\n        \n    ![image.png](https:\/\/images.viblo.asia\/2de8b1c6-4abf-43b6-824e-8a91d050c604.png)\n    \n    3.  Chuy\u1ec3n thanh n\u00e0y xu\u1ed1ng d\u01b0\u1edbi thanh Ribbon (Ch\u1ecdn _Show Below the Ribbon_) \u0111\u1ec3 r\u00fat ng\u1eafn qu\u00e3ng \u0111\u01b0\u1eddng di chu\u1ed9t.\n        \n ![image.png](https:\/\/images.viblo.asia\/84ccb9c0-6c12-477d-b5ee-a876d6cdf110.png)\n\n#### Ph\u1ea7n C: Status Bar \u2013 \"Thanh tr\u1ea1ng th\u00e1i\" \u1edf \u0111\u00e1y m\u00e0n h\u00ecnh\n\n-   **V\u1ecb tr\u00ed:** Thanh ngang n\u1eb1m d\u01b0\u1edbi c\u00f9ng c\u1ee7a c\u1eeda s\u1ed5 Word.\n    \n![image.png](https:\/\/images.viblo.asia\/3711cf21-5cb5-4b04-aa49-275feaaa9b10.png)\n    \n-   **C\u00e1c th\u00f4ng s\u1ed1 c\u1ef1c k\u1ef3 h\u1eefu \u00edch:**\n    \n    -   **G\u00f3c tr\u00e1i:** B\u00e1o s\u1ed1 trang hi\u1ec7n t\u1ea1i (_Page 1 of 10_), t\u1ed5ng s\u1ed1 t\u1eeb \u0111\u00e3 g\u00f5 (_Words_ - c\u1ef1c k\u1ef3 quan tr\u1ecdng khi vi\u1ebft b\u00e0i gi\u1edbi h\u1ea1n s\u1ed1 t\u1eeb), v\u00e0 ki\u1ec3m tra l\u1ed7i ch\u00ednh t\u1ea3.\n        \n    -   **G\u00f3c ph\u1ea3i:** 3 ch\u1ebf \u0111\u1ed9 xem nhanh (_Read Mode, Print Layout, Web Layout_) v\u00e0 thanh tr\u01b0\u1ee3t **Zoom** (Ph\u00f3ng to\/thu nh\u1ecf trang gi\u1ea5y).\n        \n-   **M\u1eb9o th\u1ef1c chi\u1ebfn:**\n    \n    -   Gi\u1eef ph\u00edm **`Ctrl` + L\u0103n con l\u0103n chu\u1ed9t** \u0111\u1ec3 ph\u00f3ng to\/thu nh\u1ecf trang gi\u1ea5y si\u00eau t\u1ed1c thay v\u00ec ph\u1ea3i k\u00e9o thanh Zoom.\n        \n    -   **Click chu\u1ed9t ph\u1ea3i v\u00e0o thanh Status Bar** \u0111\u1ec3 b\u1eadt th\u00eam t\u00ednh n\u0103ng **Section** (hi\u1ec3n th\u1ecb ph\u00e2n v\u00f9ng trang) v\u00e0 **Page Number** \u2013 b\u01b0\u1edbc \u0111\u1ec7m c\u1ef1c k\u1ef3 quan tr\u1ecdng cho c\u00e1c b\u00e0i h\u1ecdc \u0111\u00e1nh s\u1ed1 trang n\u00e2ng cao v\u1ec1 sau.\n        \n\n### 3. B\u00e0i t\u1eadp th\u1ef1c h\u00e0nh cu\u1ed1i b\u00e0i \n\nH\u00e3y th\u1eed th\u1ef1c h\u00e0nh 3 b\u00e0i t\u1eadp d\u01b0\u1edbi \u0111\u00e2y:\n\n1.  Nh\u1ea5n th\u1eed `Ctrl + F1` hai l\u1ea7n \u0111\u1ec3 xem thanh Ribbon \u1ea9n\/hi\u1ec7n nh\u01b0 th\u1ebf n\u00e0o.\n    \n2.  \u0110\u01b0a n\u00fat **Ch\u00e8n b\u1ea3ng (Table)** l\u00ean thanh Quick Access Toolbar b\u1eb1ng thao t\u00e1c click chu\u1ed9t ph\u1ea3i.\n    \n3.  Click chu\u1ed9t ph\u1ea3i v\u00e0o thanh Status Bar b\u00ean d\u01b0\u1edbi v\u00e0 t\u00edch b\u1eadt m\u1ee5c **Section** l\u00ean.","published_at":"2026-10-25T10:18:07.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T15:00:09.000000Z","edited_at":"2026-10-25T12:29:43.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":5,"points":0,"views_count":12,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/a0983d56-0e70-4260-969b-fc90c74515e3.png","user":{"data":{"id":182732,"url":"https:\/\/viblo.asia\/u\/Hieumn","avatar":"b79a0c92-fb82-49df-bda1-2f51c8e45300.jpg","name":"Nguyen Hoang","username":"Hieumn","followers_count":0,"reputation":2,"posts_count":50,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"microsoft","name":"Microsoft"}]},"commentators":{"data":[]}},{"id":109603,"title":"Greenplum Database B\u00e0i h\u1ecdc 22: External Tables (Readable & Writable): Truy v\u1ea5n tr\u1ef1c ti\u1ebfp file CSV\/Text b\u00ean ngo\u00e0i m\u00e0 kh\u00f4ng c\u1ea7n Import","slug":"OXLA0W2kJGr","url":"https:\/\/viblo.asia\/p\/greenplum-database-bai-hoc-22-external-tables-readable-writable-truy-van-truc-tiep-file-csvtext-ben-ngoai-ma-khong-can-import-OXLA0W2kJGr","user_id":182732,"moderation":null,"transliterated":"greenplum-database-bai-hoc-22-external-tables-readable-writable-truy-van-truc-tiep-file-csvtext-ben-ngoai-ma-khong-can-import","contents_short":"\u1ede B\u00e0i h\u1ecdc 21, ch\u00fang ta \u0111\u00e3 l\u00e0m quen v\u1edbi ti\u1ebfn tr\u00ecnh gpfdist nh\u1eb1m ph\u00e1 v\u1ee1 n\u00fat th\u1eaft c\u1ed5 chai c\u1ee7a Master Node khi n\u1ea1p d\u1eef li\u1ec7u. Tuy nhi\u00ean, c\u00f4ng c\u1ee5 k\u1ebft n\u1ed1i \u0111\u1eafc l\u1ef1c nh\u1ea5t gi\u00fap Greenplum bi\u1ebfn c\u00e1c t\u1ec7p tin b\u00ean ngo\u00e0i th\u00e0nh \"m\u1ed9t ph\u1ea7n c\u1ee7a c\u01a1 s\u1edf d\u1eef li\u1ec7u\" ch\u00ednh l\u00e0 h\u1ec7 th\u1ed1ng External Tables (B\u1ea3ng ngo\u00e0i).\n\nTrong c\u00e1c c\u01a1 s\u1edf d\u1eef li\u1ec7u quan h\u1ec7 truy\u1ec1n th\u1ed1ng, \u0111\u1ec3 ph\u00e2n t\u00edch m\u1ed9t file CSV dung l\u01b0\u1ee3ng l\u1edbn, b\u1ea1n b\u1eaft bu\u1ed9c ph\u1ea3i t\u1ea1o b...","contents":"\u1ede B\u00e0i h\u1ecdc 21, ch\u00fang ta \u0111\u00e3 l\u00e0m quen v\u1edbi ti\u1ebfn tr\u00ecnh `gpfdist` nh\u1eb1m ph\u00e1 v\u1ee1 n\u00fat th\u1eaft c\u1ed5 chai c\u1ee7a Master Node khi n\u1ea1p d\u1eef li\u1ec7u. Tuy nhi\u00ean, c\u00f4ng c\u1ee5 k\u1ebft n\u1ed1i \u0111\u1eafc l\u1ef1c nh\u1ea5t gi\u00fap Greenplum bi\u1ebfn c\u00e1c t\u1ec7p tin b\u00ean ngo\u00e0i th\u00e0nh \"m\u1ed9t ph\u1ea7n c\u1ee7a c\u01a1 s\u1edf d\u1eef li\u1ec7u\" ch\u00ednh l\u00e0 h\u1ec7 th\u1ed1ng **External Tables (B\u1ea3ng ngo\u00e0i)**.\n\nTrong c\u00e1c c\u01a1 s\u1edf d\u1eef li\u1ec7u quan h\u1ec7 truy\u1ec1n th\u1ed1ng, \u0111\u1ec3 ph\u00e2n t\u00edch m\u1ed9t file CSV dung l\u01b0\u1ee3ng l\u1edbn, b\u1ea1n b\u1eaft bu\u1ed9c ph\u1ea3i t\u1ea1o b\u1ea3ng r\u1ed3i th\u1ef1c hi\u1ec7n c\u00e2u l\u1ec7nh `IMPORT` ho\u1eb7c `LOAD` to\u00e0n b\u1ed9 d\u1eef li\u1ec7u v\u00e0o \u1ed5 c\u1ee9ng. V\u1edbi Greenplum, nh\u1edd c\u01a1 ch\u1ebf **External Tables**, b\u1ea1n c\u00f3 th\u1ec3 **tr\u1ef1c ti\u1ebfp truy v\u1ea5n SQL l\u00ean c\u00e1c t\u1ec7p tin CSV, Text n\u1eb1m b\u00ean ngo\u00e0i h\u1ec7 th\u1ed1ng m\u00e0 kh\u00f4ng c\u1ea7n t\u1ed1n dung l\u01b0\u1ee3ng \u0111\u0129a \u0111\u1ec3 Import tr\u01b0\u1edbc**.\n\nTrong b\u00e0i h\u1ecdc n\u00e0y, ch\u00fang ta s\u1ebd kh\u00e1m ph\u00e1 s\u1ee9c m\u1ea1nh c\u1ee7a c\u1ea3 hai lo\u1ea1i:  **Readable External Tables** v\u00e0 **Writable External Tables**.\n\n## 1. External Tables l\u00e0 g\u00ec?\n\n**External Table** l\u00e0 m\u1ed9t \u0111\u1ed1i t\u01b0\u1ee3ng \u1ea3o trong Greenplum System Catalog. V\u1ec1 m\u1eb7t logic, n\u00f3 tr\u00f4ng gi\u1ed1ng h\u1ec7t nh\u01b0 m\u1ed9t b\u1ea3ng b\u00ecnh th\u01b0\u1eddng (c\u00f3 t\u00ean c\u1ed9t, ki\u1ec3u d\u1eef li\u1ec7u, schema), nh\u01b0ng v\u1ec1 m\u1eb7t v\u1eadt l\u00fd,  **n\u00f3 kh\u00f4ng l\u01b0u tr\u1eef b\u1ea5t k\u1ef3 d\u00f2ng d\u1eef li\u1ec7u n\u00e0o tr\u00ean \u1ed5 c\u1ee9ng c\u1ee7a c\u01a1 s\u1edf d\u1eef li\u1ec7u**.\n\nThay v\u00e0o \u0111\u00f3, khi b\u1ea1n ch\u1ea1y m\u1ed9t c\u00e2u truy v\u1ea5n `SELECT` tr\u00ean External Table, Greenplum s\u1ebd tr\u1ef1c ti\u1ebfp \u0111i\u1ec1u ph\u1ed1i c\u00e1c Segment \u0111\u1ecdc d\u1eef li\u1ec7u \"on-the-fly\" t\u1eeb ngu\u1ed3n b\u00ean ngo\u00e0i (file tr\u00ean \u0111\u0129a qua `gpfdist`, qua giao th\u1ee9c Web HTTP, ho\u1eb7c t\u1eeb c\u00e1c h\u1ec7 th\u1ed1ng l\u01b0u tr\u1eef ph\u00e2n t\u00e1n).\n\n```\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                        KI\u1ebeN TR\u00daC EXTERNAL TABLES                       \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                            \u2502                \u2502\n            1. READABLE EXTERNAL TABLE        2. WRITABLE EXTERNAL TABLE\n            (\u0110\u1ecdc file b\u00ean ngo\u00e0i v\u00e0o DB)       (Xu\u1ea5t d\u1eef li\u1ec7u t\u1eeb DB ra file)\n            [File CSV\/Text] \u2500\u2500\u25ba [Greenplum]   [Greenplum] \u2500\u2500\u25ba [File CSV\/Text]\n\n```\n\n## 2. Readable External Tables: Truy v\u1ea5n file b\u00ean ngo\u00e0i nh\u01b0 b\u1ea3ng th\u1eadt\n\n### 2.1. M\u1ee5c \u0111\u00edch s\u1eed d\u1ee5ng\n\n-   Truy v\u1ea5n tr\u1ef1c ti\u1ebfp ki\u1ec3m tra n\u1ed9i dung file d\u1eef li\u1ec7u tr\u01b0\u1edbc khi quy\u1ebft \u0111\u1ecbnh n\u1ea1p v\u00e0o b\u1ea3ng ch\u00ednh.\n    \n-   Th\u1ef1c hi\u1ec7n c\u00e1c ph\u00e9p ph\u00e2n t\u00edch nhanh, b\u00e1o c\u00e1o ad-hoc tr\u00ean c\u00e1c t\u1ec7p log h\u00e0ng ng\u00e0y m\u00e0 kh\u00f4ng l\u00e0m t\u1ed1n dung l\u01b0\u1ee3ng l\u01b0u tr\u1eef \u0111\u0129a c\u1ee7a Data Warehouse.\n    \n-   Ph\u1ee5c v\u1ee5 qu\u00e1 tr\u00ecnh ETL (Extract - Transform - Load): \u0110\u1ecdc d\u1eef li\u1ec7u t\u1eeb file ngo\u00e0i, l\u00e0m s\u1ea1ch (Transform) r\u1ed3i ghi v\u00e0o b\u1ea3ng \u0111\u00edch.\n    \n\n### 2.2. C\u00fa ph\u00e1p th\u1ef1c chi\u1ebfn Readable External Table\n\n\u0110\u1ec3 t\u1ea1o m\u1ed9t b\u1ea3ng \u0111\u1ecdc ngo\u00e0i k\u1ebft n\u1ed1i th\u00f4ng qua `gpfdist` (\u0111\u00e3 h\u1ecdc \u1edf B\u00e0i 21):\n\nSQL\n\n```\nCREATE READABLE EXTERNAL TABLE ext_raw_orders (\n    order_id BIGINT,\n    customer_id BIGINT,\n    status VARCHAR(20),\n    order_date TIMESTAMP\n) \nLOCATION ('gpfdist:\/\/10.10.10.10:8080\/raw_orders_*.csv')\nFORMAT 'TEXT' (DELIMITER ',' NULL '' ESCAPE '\\')\nENCODING 'UTF8'\nLOG ERRORS INTO err_log_orders SEGMENT REJECT LIMIT 10 PERCENT;\n\n```\n\n### \u0110i\u1ec3m \u0111\u1eb7c bi\u1ec7t trong c\u00fa ph\u00e1p:\n\n-   **`LOCATION`**: Ch\u1ec9 \u0111\u1ecbnh giao th\u1ee9c v\u00e0 \u0111\u1ecba ch\u1ec9 ngu\u1ed3n d\u1eef li\u1ec7u (h\u1ed7 tr\u1ee3 `gpfdist:\/\/`,  `gpfdists:\/\/` b\u1ea3o m\u1eadt, ho\u1eb7c `file:\/\/` n\u1ebfu file n\u1eb1m s\u1eb5n tr\u00ean m\u1ecdi Segment Host).\n    \n-   **`LOG ERRORS INTO ... SEGMENT REJECT LIMIT`**: \u0110\u00e2y l\u00e0 t\u00ednh n\u0103ng x\u1eed l\u00fd d\u1eef li\u1ec7u b\u1ea9n c\u1ef1c k\u1ef3 th\u00f4ng minh c\u1ee7a Greenplum. N\u1ebfu file CSV c\u00f3 c\u00e1c d\u00f2ng b\u1ecb l\u1ed7i \u0111\u1ecbnh d\u1ea1ng (sai ki\u1ec3u d\u1eef li\u1ec7u, thi\u1ebfu c\u1ed9t), thay v\u00ec l\u00e0m s\u1eadp to\u00e0n b\u1ed9 c\u00e2u l\u1ec7nh, Greenplum cho ph\u00e9p ghi nh\u1eadn c\u00e1c d\u00f2ng l\u1ed7i \u0111\u00f3 v\u00e0o b\u1ea3ng log ri\u00eang v\u00e0 ch\u1ec9 h\u1ee7y b\u1ecf n\u1ebfu t\u1ef7 l\u1ec7 l\u1ed7i v\u01b0\u1ee3t qu\u00e1 gi\u1edbi h\u1ea1n cho ph\u00e9p (v\u00ed d\u1ee5 10%).\n    \n\n## 3. Writable External Tables: Xu\u1ea5t d\u1eef li\u1ec7u t\u1eeb Greenplum ra file ngo\u00e0i\n\nKh\u00f4ng ch\u1ec9 \u0111\u1ecdc, Greenplum c\u00f2n cung c\u1ea5p **Writable External Tables** cho ph\u00e9p b\u1ea1n xu\u1ea5t d\u1eef li\u1ec7u t\u1eeb c\u00e1c b\u1ea3ng b\u00ean trong c\u01a1 s\u1edf d\u1eef li\u1ec7u ra th\u00e0nh c\u00e1c t\u1ec7p tin b\u00ean ngo\u00e0i th\u00f4ng qua ti\u1ebfn tr\u00ecnh `gpfdist`.\n\n### 3.1. M\u1ee5c \u0111\u00edch s\u1eed d\u1ee5ng\n\n-   Tr\u00edch xu\u1ea5t d\u1eef li\u1ec7u l\u1ecbch s\u1eed (Archive) ra c\u00e1c file CSV \u0111\u1ec3 l\u01b0u tr\u1eef l\u1ea1nh.\n    \n-   Xu\u1ea5t b\u00e1o c\u00e1o, k\u1ebft qu\u1ea3 ph\u00e2n t\u00edch sang c\u00e1c h\u1ec7 th\u1ed1ng b\u00ean ngo\u00e0i \u0111\u1ec3 ph\u1ee5c v\u1ee5 c\u00e1c b\u00ean li\u00ean quan.\n    \n-   T\u1ed1i \u01b0u h\u00f3a quy tr\u00ecnh truy\u1ec1n t\u1ea3i d\u1eef li\u1ec7u gi\u1eefa c\u00e1c c\u1ee5m c\u01a1 s\u1edf d\u1eef li\u1ec7u kh\u00e1c nhau.\n    \n\n### 3.2. C\u00fa ph\u00e1p th\u1ef1c chi\u1ebfn Writable External Table\n\nSQL\n\n```\nCREATE WRITABLE EXTERNAL TABLE ext_export_orders (\n    order_id BIGINT,\n    customer_id BIGINT,\n    total_amount NUMERIC(12,2)\n) \nLOCATION ('gpfdist:\/\/10.10.10.10:8080\/exported_orders.csv')\nFORMAT 'TEXT' (DELIMITER ',');\n\n```\n\n### C\u00e1ch s\u1eed d\u1ee5ng \u0111\u1ec3 xu\u1ea5t d\u1eef li\u1ec7u:\n\nSau khi t\u1ea1o xong Writable External Table, vi\u1ec7c tr\u00edch xu\u1ea5t d\u1eef li\u1ec7u h\u00e0ng tri\u1ec7u b\u1ea3n ghi t\u1eeb b\u1ea3ng ch\u00ednh ra file ch\u1ec9 \u0111\u01a1n gi\u1ea3n l\u00e0 m\u1ed9t c\u00e2u l\u1ec7nh `INSERT` \u0111\u1ea3o chi\u1ec1u:\n\nSQL\n\n```\n-- D\u1eef li\u1ec7u t\u1eeb b\u1ea3ng Fact s\u1ebd \u0111\u01b0\u1ee3c c\u00e1c Segment \u0111\u1ed3ng lo\u1ea1t tr\u00edch xu\u1ea5t v\u00e0 \u0111\u1ea9y ra file qua gpfdist\nINSERT INTO ext_export_orders \nSELECT order_id, customer_id, total_amount \nFROM fact_orders \nWHERE created_at < '2025-01-01';\n\n```\n\n## 4. T\u00f3m t\u1eaft \u01b0u \u0111i\u1ec3m v\u01b0\u1ee3t tr\u1ed9i c\u1ee7a External Tables\n\n1.  **Ti\u1ebft ki\u1ec7m t\u00e0i nguy\u00ean \u0111\u0129a:** Kh\u00f4ng c\u1ea7n t\u1ed1n kh\u00f4ng gian l\u01b0u tr\u1eef tr\u00f9ng l\u1eb7p khi c\u1ea7n ph\u00e2n t\u00edch t\u1ea1m th\u1eddi d\u1eef li\u1ec7u t\u1eeb file.\n    \n2.  **Hi\u1ec7u n\u0103ng song song h\u00f3a cao:** D\u1eef li\u1ec7u \u0111\u01b0\u1ee3c \u0111\u1ecdc ho\u1eb7c ghi \u0111\u1ed3ng th\u1eddi b\u1edfi t\u1ea5t c\u1ea3 c\u00e1c ti\u1ebfn tr\u00ecnh Segment th\u00f4ng qua m\u1ea1ng n\u1ed9i b\u1ed9, t\u1eadn d\u1ee5ng t\u1ed1i \u0111a b\u0103ng th\u00f4ng ph\u1ea7n c\u1ee9ng.\n    \n3.  **Linh ho\u1ea1t trong ki\u1ebfn tr\u00fac ETL:** Gi\u00fap \u0111\u01a1n gi\u1ea3n h\u00f3a c\u00e1c lu\u1ed3ng x\u1eed l\u00fd d\u1eef li\u1ec7u l\u1edbn, k\u1ebft h\u1ee3p ho\u00e0n h\u1ea3o gi\u1eefa th\u1ebf gi\u1edbi t\u1ec7p tin b\u00ean ngo\u00e0i v\u00e0 c\u01a1 s\u1edf d\u1eef li\u1ec7u ph\u00e2n t\u00e1n.\n    \n\n## T\u00f3m t\u1eaft B\u00e0i h\u1ecdc 22\n\n-   **External Tables** l\u00e0 b\u1ea3ng \u1ea3o trong Greenplum cho ph\u00e9p truy v\u1ea5n ho\u1eb7c ghi d\u1eef li\u1ec7u tr\u1ef1c ti\u1ebfp ra c\u00e1c t\u1ec7p b\u00ean ngo\u00e0i (CSV, Text) m\u00e0 kh\u00f4ng c\u1ea7n Import v\u00e0o \u0111\u0129a c\u1ee5c b\u1ed9 c\u1ee7a database.\n    \n-   **Readable External Tables** d\u00f9ng \u0111\u1ec3 \u0111\u1ecdc file b\u00ean ngo\u00e0i k\u1ebft h\u1ee3p c\u01a1 ch\u1ebf l\u1ecdc l\u1ed7i th\u00f4ng minh (`LOG ERRORS`).\n    \n-   **Writable External Tables** d\u00f9ng \u0111\u1ec3 tr\u00edch xu\u1ea5t d\u1eef li\u1ec7u t\u1eeb b\u1ea3ng trong c\u01a1 s\u1edf d\u1eef li\u1ec7u ra file b\u00ean ngo\u00e0i th\u00f4ng qua l\u1ec7nh `INSERT`.\n    \n\n_\u1ede b\u00e0i h\u1ecdc ti\u1ebfp theo (**B\u00e0i h\u1ecdc 23**), ch\u00fang ta s\u1ebd b\u01b0\u1edbc sang m\u1ed9t c\u1ed5ng k\u1ebft n\u1ed1i \u0111a n\u0103ng h\u01a1n n\u1eefa trong h\u1ec7 sinh th\u00e1i Big Data: **Greenplum Platform Extension Framework (PXF): C\u1ed5ng k\u1ebft n\u1ed1i \u0111a n\u0103ng v\u1edbi th\u1ebf gi\u1edbi b\u00ean ngo\u00e0i**._","published_at":"2026-10-25T09:47:31.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T14:41:03.000000Z","edited_at":"2026-10-24T08:27:27.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":6,"points":0,"views_count":11,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/7c7b4bc1-4051-4a2c-af14-05c9ab9e9556.png","user":{"data":{"id":182732,"url":"https:\/\/viblo.asia\/u\/Hieumn","avatar":"b79a0c92-fb82-49df-bda1-2f51c8e45300.jpg","name":"Nguyen Hoang","username":"Hieumn","followers_count":0,"reputation":2,"posts_count":50,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"cloud-database","name":"cloud database"}]},"commentators":{"data":[]}},{"id":109602,"title":"Greenplum Database B\u00e0i h\u1ecdc 21: Ki\u1ebfn tr\u00fac gpfdist: Ph\u00e1 v\u1ee1 n\u00fat th\u1eaft c\u1ed5 chai \u1edf Master b\u1eb1ng c\u00e1ch n\u1ea1p song song tr\u1ef1c ti\u1ebfp v\u00e0o c\u00e1c Segment","slug":"kNLr3elWVgA","url":"https:\/\/viblo.asia\/p\/greenplum-database-bai-hoc-21-kien-truc-gpfdist-pha-vo-nut-that-co-chai-o-master-bang-cach-nap-song-song-truc-tiep-vao-cac-segment-kNLr3elWVgA","user_id":182732,"moderation":null,"transliterated":"greenplum-database-bai-hoc-21-kien-truc-gpfdist-pha-vo-nut-that-co-chai-o-master-bang-cach-nap-song-song-truc-tiep-vao-cac-segment","contents_short":"\u1ede B\u00e0i h\u1ecdc 20, ch\u00fang ta \u0111\u00e3 th\u1ea5y l\u1ec7nh COPY truy\u1ec1n th\u1ed1ng gi\u00fap n\u1ea1p d\u1eef li\u1ec7u nhanh h\u01a1n INSERT r\u1ea5t nhi\u1ec1u, nh\u01b0ng l\u1ea1i m\u1eafc ph\u1ea3i m\u1ed9t \"t\u1eed huy\u1ec7t\" ch\u00ed m\u1ea1ng:  To\u00e0n b\u1ed9 t\u1ec7p d\u1eef li\u1ec7u kh\u1ed5ng l\u1ed3 b\u1eaft bu\u1ed9c ph\u1ea3i \u0111i qua Master Node. Master Node ph\u1ea3i g\u00e1nh v\u00e1c to\u00e0n b\u1ed9 c\u00f4ng vi\u1ec7c ph\u00e2n t\u00edch, t\u00ednh to\u00e1n h\u00e0m b\u0103m (Hash) v\u00e0 ph\u00e2n ph\u1ed1i xu\u1ed1ng c\u00e1c Segment, nhanh ch\u00f3ng tr\u1edf th\u00e0nh n\u00fat th\u1eaft c\u1ed5 chai ph\u1ea7n c\u1ee9ng khi \u0111\u1ed1i m\u1eb7t v\u1edbi d\u1eef li\u1ec7u h\u00e0ng ...","contents":"\u1ede B\u00e0i h\u1ecdc 20, ch\u00fang ta \u0111\u00e3 th\u1ea5y l\u1ec7nh `COPY` truy\u1ec1n th\u1ed1ng gi\u00fap n\u1ea1p d\u1eef li\u1ec7u nhanh h\u01a1n `INSERT` r\u1ea5t nhi\u1ec1u, nh\u01b0ng l\u1ea1i m\u1eafc ph\u1ea3i m\u1ed9t \"t\u1eed huy\u1ec7t\" ch\u00ed m\u1ea1ng:  **To\u00e0n b\u1ed9 t\u1ec7p d\u1eef li\u1ec7u kh\u1ed5ng l\u1ed3 b\u1eaft bu\u1ed9c ph\u1ea3i \u0111i qua Master Node**. Master Node ph\u1ea3i g\u00e1nh v\u00e1c to\u00e0n b\u1ed9 c\u00f4ng vi\u1ec7c ph\u00e2n t\u00edch, t\u00ednh to\u00e1n h\u00e0m b\u0103m (Hash) v\u00e0 ph\u00e2n ph\u1ed1i xu\u1ed1ng c\u00e1c Segment, nhanh ch\u00f3ng tr\u1edf th\u00e0nh n\u00fat th\u1eaft c\u1ed5 chai ph\u1ea7n c\u1ee9ng khi \u0111\u1ed1i m\u1eb7t v\u1edbi d\u1eef li\u1ec7u h\u00e0ng ch\u1ee5c Gigabyte.\n\n\u0110\u1ec3 ph\u00e1 v\u1ee1 ho\u00e0n to\u00e0n n\u00fat th\u1eaft c\u1ed5 chai n\u00e0y v\u00e0 khai th\u00e1c t\u1ed1i \u0111a s\u1ee9c m\u1ea1nh n\u1ea1p d\u1eef li\u1ec7u song song c\u1ee7a ki\u1ebfn tr\u00fac MPP, Greenplum cung c\u1ea5p m\u1ed9t ti\u1ec7n \u00edch \u0111\u1ed9c quy\u1ec1n c\u1ef1c k\u1ef3 m\u1ea1nh m\u1ebd mang t\u00ean **`gpfdist`**. Trong b\u00e0i h\u1ecdc n\u00e0y, ch\u00fang ta s\u1ebd m\u1ed5 x\u1ebb ki\u1ebfn tr\u00fac ho\u1ea1t \u0111\u1ed9ng c\u1ee7a `gpfdist` v\u00e0 c\u00e1ch n\u00f3 gi\u00fap n\u1ea1p h\u00e0ng Terabyte d\u1eef li\u1ec7u ch\u1ec9 trong v\u00e0i ph\u00fat.\n\n## 1. V\u1ea5n \u0111\u1ec1 c\u1ed1t l\u00f5i: L\u00e0m sao \u0111\u1ec3 n\u1ea1p d\u1eef li\u1ec7u kh\u00f4ng qua Master?\n\nTrong m\u1ed9t c\u1ee5m Greenplum chu\u1ea9n, c\u00e1c m\u00e1y ch\u1ee7 Segment (`sdw1`,  `sdw2`...) m\u1edbi l\u00e0 nh\u1eefng \"c\u00f4ng nh\u00e2n\" s\u1edf h\u1eefu \u1ed5 c\u1ee9ng dung l\u01b0\u1ee3ng l\u1edbn, card m\u1ea1ng t\u1ed1c \u0111\u1ed9 cao v\u00e0 s\u1ee9c m\u1ea1nh t\u00ednh to\u00e1n th\u1ef1c s\u1ef1.\n\nN\u1ebfu ch\u00fang ta c\u00f3 m\u1ed9t t\u1ec7p d\u1eef li\u1ec7u log n\u1eb7ng **100 GB** n\u1eb1m tr\u00ean m\u00e1y ch\u1ee7 ETL b\u00ean ngo\u00e0i, m\u1ee5c ti\u00eau l\u00fd t\u01b0\u1edfng nh\u1ea5t l\u00e0:\n\n-   Kh\u00f4ng \u0111\u1ea9y to\u00e0n b\u1ed9 100 GB \u0111\u00f3 d\u1ed3n c\u1ee5c v\u00e0o Master.\n    \n-   Thay v\u00e0o \u0111\u00f3,  **chia nh\u1ecf t\u1ec7p d\u1eef li\u1ec7u ra v\u00e0 cho ph\u00e9p t\u1ea5t c\u1ea3 c\u00e1c Segment Hosts \u0111\u1ed3ng lo\u1ea1t ch\u1ee7 \u0111\u1ed9ng k\u1ebft n\u1ed1i v\u00e0o ngu\u1ed3n d\u1eef li\u1ec7u**, m\u1ed7i Segment t\u1ef1 \u0111\u1ecdc ph\u1ea7n vi\u1ec7c c\u1ee7a m\u00ecnh, t\u1ef1 b\u0103m Hash v\u00e0 t\u1ef1 ghi th\u1eb3ng xu\u1ed1ng \u0111\u0129a c\u1ee7a n\u00f3.\n    \n\n\u0110\u00f3 ch\u00ednh x\u00e1c l\u00e0 s\u1ee9 m\u1ec7nh sinh ra c\u1ee7a **`gpfdist`**.\n\n## 2. Gi\u1ea3i ph\u1eabu ki\u1ebfn tr\u00fac `gpfdist` (Greenplum File Distribution Program)\n\n`gpfdist` l\u00e0 m\u1ed9t ti\u1ebfn tr\u00ecnh m\u00e1y ch\u1ee7 HTTP\/File Server si\u00eau nh\u1eb9, \u0111\u01b0\u1ee3c vi\u1ebft b\u1eb1ng ng\u00f4n ng\u1eef C, ch\u1ea1y tr\u1ef1c ti\u1ebfp tr\u00ean m\u00e1y ch\u1ee7 ch\u1ee9a t\u1ec7p d\u1eef li\u1ec7u (c\u00f3 th\u1ec3 l\u00e0 m\u00e1y ch\u1ee7 ETL ri\u00eang bi\u1ec7t ho\u1eb7c ch\u00ednh m\u00e1y Master).\n\n```\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                        KI\u1ebeN TR\u00daC N\u1ea0P D\u1eee LI\u1ec6U GPFDIST                     \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                            \u2502                        \u2502\n       [ M\u00e1y ch\u1ee7 ch\u1ee9a File CSV (ETL Server) ]        \u2502\n       \u2022 Ch\u1ea1y ti\u1ebfn tr\u00ecnh: gpfdist (C\u1ed5ng 8080)        \u2502\n       \u2022 Chia nh\u1ecf file th\u00e0nh nhi\u1ec1u lu\u1ed3ng \u0111\u1ecdc         \u2502\n                            \u2502                        \u2502\n            \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510        \u2502\n            \u25bc                               \u25bc        \u2502\n    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510               \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u2502\n    \u2502 Segment Host 1\u2502               \u2502 Segment Host 2\u2502\u2502\n    \u2502 (Segment 0, 1)\u2502               \u2502 (Segment 2, 3)\u2502\u2502\n    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518               \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\u2502\n     (\u0110\u1ed3ng lo\u1ea1t k\u1ebft n\u1ed1i song song t\u1edbi gpfdist qua HTTP)\n\n```\n\n### C\u01a1 ch\u1ebf ho\u1ea1t \u0111\u1ed9ng c\u1ee7a `gpfdist`:\n\n1.  **Kh\u1edfi \u0111\u1ed9ng Server:** DBA b\u1eadt ti\u1ebfn tr\u00ecnh `gpfdist` tr\u1ecf v\u00e0o th\u01b0 m\u1ee5c ch\u1ee9a c\u00e1c file d\u1eef li\u1ec7u tr\u00ean m\u00e1y ch\u1ee7 ETL (v\u00ed d\u1ee5: ch\u1ea1y \u1edf c\u1ed5ng `8080`).\n    \n2.  **Khai b\u00e1o External Table:** Tr\u00ean c\u01a1 s\u1edf d\u1eef li\u1ec7u Greenplum, DBA t\u1ea1o m\u1ed9t b\u1ea3ng ngo\u00e0i (`READABLE EXTERNAL TABLE`) tr\u1ecf \u0111\u1ebfn \u0111\u1ecba ch\u1ec9 c\u1ee7a ti\u1ebfn tr\u00ecnh `gpfdist` \u0111\u00f3.\n    \n3.  **\u0110\u1ecdc d\u1eef li\u1ec7u song song (Parallel Stream Reading):** Khi b\u1ea1n ch\u1ea1y c\u00e2u l\u1ec7nh `SELECT` ho\u1eb7c `INSERT INTO target_table SELECT * FROM external_table`,  **t\u1ea5t c\u1ea3 c\u00e1c ti\u1ebfn tr\u00ecnh Segment tr\u00ean to\u00e0n c\u1ee5m s\u1ebd \u0111\u1ed3ng lo\u1ea1t m\u1edf k\u1ebft n\u1ed1i HTTP song song** tr\u1ef1c ti\u1ebfp \u0111\u1ebfn `gpfdist`.\n    \n4.  **Kh\u00f4ng qua Master:**  `gpfdist` t\u1ef1 \u0111\u1ed9ng chia nh\u1ecf file d\u1eef li\u1ec7u, ph\u00e2n ph\u00e1t c\u00e1c kh\u1ed1i kh\u00e1c nhau cho c\u00e1c Segment \u0111ang y\u00eau c\u1ea7u. M\u1ed7i Segment t\u1ef1 nh\u1eadn d\u1eef li\u1ec7u, t\u1ef1 ph\u00e2n t\u00edch \u0111\u1ecbnh d\u1ea1ng v\u00e0 ghi th\u1eb3ng v\u00e0o \u1ed5 c\u1ee9ng c\u1ee7a n\u00f3. Master l\u00fac n\u00e0y ch\u1ec9 \u0111\u00f3ng vai tr\u00f2 gi\u00e1m s\u00e1t, ho\u00e0n to\u00e0n kh\u00f4ng b\u1ecb v\u01b0\u1edbng v\u00e0o lu\u1ed3ng d\u1eef li\u1ec7u th\u00f4!\n    \n\n## 3. C\u00e1c \u01b0u \u0111i\u1ec3m v\u01b0\u1ee3t tr\u1ed9i c\u1ee7a `gpfdist`\n\n-   **T\u1ed1c \u0111\u1ed9 \u0111\u1ecdc\/ghi \u0111\u1ea1t ng\u01b0\u1ee1ng ph\u1ea7n c\u1ee9ng (Line-rate speed):** V\u00ec s\u1eed d\u1ee5ng nhi\u1ec1u lu\u1ed3ng k\u1ebft n\u1ed1i song song t\u1eeb t\u1ea5t c\u1ea3 c\u00e1c Segment c\u00f9ng m\u1ed9t l\u00fac,  `gpfdist` t\u1eadn d\u1ee5ng tri\u1ec7t \u0111\u1ec3 b\u0103ng th\u00f4ng m\u1ea1ng v\u00e0 t\u1ed1c \u0111\u1ed9 \u0111\u1ecdc c\u1ee7a \u1ed5 c\u1ee9ng, lo\u1ea1i b\u1ecf ho\u00e0n to\u00e0n hi\u1ec7n t\u01b0\u1ee3ng ngh\u1ebdn c\u1ed5 chai.\n    \n-   **C\u01a1 ch\u1ebf c\u00e2n b\u1eb1ng t\u1ea3i t\u1ef1 \u0111\u1ed9ng (Load Balancing):** N\u1ebfu m\u1ed9t Segment ho\u00e0n th\u00e0nh vi\u1ec7c \u0111\u1ecdc ph\u1ea7n d\u1eef li\u1ec7u c\u1ee7a n\u00f3 nhanh h\u01a1n c\u00e1c Segment kh\u00e1c,  `gpfdist` s\u1ebd t\u1ef1 \u0111\u1ed9ng c\u1ea5p ph\u00e1t ti\u1ebfp c\u00e1c kh\u1ed1i d\u1eef li\u1ec7u ti\u1ebfp theo cho Segment \u0111\u00f3, \u0111\u1ea3m b\u1ea3o kh\u00f4ng c\u00f3 m\u00e1y n\u00e0o ph\u1ea3i ng\u1ed3i ch\u01a1i.\n    \n-   **X\u1eed l\u00fd l\u1ed7i th\u00f4ng minh (Fault Tolerance):**  `gpfdist` cho ph\u00e9p c\u1ea5u h\u00ecnh gi\u1edbi h\u1ea1n s\u1ed1 l\u01b0\u1ee3ng d\u00f2ng d\u1eef li\u1ec7u b\u1ecb l\u1ed7i \u0111\u1ecbnh d\u1ea1ng (bad rows). N\u1ebfu t\u1ec7p CSV c\u00f3 m\u1ed9t v\u00e0i d\u00f2ng b\u1ecb l\u1ec7ch c\u1ed9t, Greenplum c\u00f3 th\u1ec3 ghi nh\u1eadn c\u00e1c d\u00f2ng l\u1ed7i \u0111\u00f3 ra m\u1ed9t b\u1ea3ng log ri\u00eang (`LOG ERRORS`) m\u00e0 kh\u00f4ng l\u00e0m gi\u00e1n \u0111o\u1ea1n to\u00e0n b\u1ed9 ti\u1ebfn tr\u00ecnh n\u1ea1p d\u1eef li\u1ec7u h\u00e0ng tri\u1ec7u d\u00f2ng.\n    \n\n## 4. C\u00fa ph\u00e1p th\u1ef1c chi\u1ebfn: S\u1eed d\u1ee5ng `gpfdist` v\u00e0 External Tables\n\n\u0110\u1ec3 n\u1ea1p d\u1eef li\u1ec7u b\u1eb1ng `gpfdist`, ch\u00fang ta th\u1ef1c hi\u1ec7n qua 3 b\u01b0\u1edbc \u0111\u01a1n gi\u1ea3n:\n\n### B\u01b0\u1edbc 1: Kh\u1edfi \u0111\u1ed9ng ti\u1ebfn tr\u00ecnh `gpfdist` tr\u00ean m\u00e1y ch\u1ee7 ch\u1ee9a file d\u1eef li\u1ec7u\n\n\u0110\u0103ng nh\u1eadp v\u00e0o m\u00e1y ch\u1ee7 ch\u1ee9a c\u00e1c file CSV (v\u00ed d\u1ee5 th\u01b0 m\u1ee5c `\/data\/etl_files`) v\u00e0 ch\u1ea1y l\u1ec7nh:\n\nBash\n\n```\ngpfdist -d \/data\/etl_files -p 8080 &\n\n```\n\n### B\u01b0\u1edbc 2: T\u1ea1o External Table tr\u1ecf t\u1edbi `gpfdist` tr\u00ean Greenplum\n\nTr\u00ean giao di\u1ec7n d\u00f2ng l\u1ec7nh `psql` c\u1ee7a Greenplum, t\u1ea1o m\u1ed9t b\u1ea3ng ngo\u00e0i li\u00ean k\u1ebft v\u1edbi \u0111\u1ecba ch\u1ec9 c\u1ee7a `gpfdist`:\n\nSQL\n\n```\nCREATE READABLE EXTERNAL TABLE ext_fact_transactions (\n    transaction_id BIGINT,\n    user_id BIGINT,\n    amount NUMERIC(12,2),\n    created_at TIMESTAMP\n) \nLOCATION ('gpfdist:\/\/etl-server-ip:8080\/transactions_*.csv')\nFORMAT 'TEXT' (DELIMITER ',' NULL '');\n\n```\n\n### B\u01b0\u1edbc 3: N\u1ea1p d\u1eef li\u1ec7u v\u00e0o b\u1ea3ng ch\u00ednh ch\u1ec9 b\u1eb1ng 1 c\u00e2u l\u1ec7nh SQL duy nh\u1ea5t\n\nB\u00e2y gi\u1edd, b\u1ea1n ch\u1ec9 c\u1ea7n \u0111\u1ed5 d\u1eef li\u1ec7u t\u1eeb b\u1ea3ng ngo\u00e0i v\u00e0o b\u1ea3ng \u0111\u00edch ch\u00ednh th\u1ee9c (`fact_transactions`) v\u1edbi t\u1ed1c \u0111\u1ed9 cao nh\u1ea5t:\n\nSQL\n\n```\nINSERT INTO fact_transactions \nSELECT * FROM ext_fact_transactions;\n\n```\n\n_Ngay kho\u1ea3nh kh\u1eafc b\u1ea1n \u1ea5n Enter, to\u00e0n b\u1ed9 c\u00e1c Segment trong c\u1ee5m s\u1ebd \u0111\u1ed3ng lo\u1ea1t \"lao v\u00e0o\" `gpfdist` \u0111\u1ec3 k\u00e9o d\u1eef li\u1ec7u v\u1ec1 n\u1ea1p song song._\n\n## T\u00f3m t\u1eaft B\u00e0i h\u1ecdc 21\n\n-   **`gpfdist`** l\u00e0 c\u00f4ng c\u1ee5 ph\u00e2n ph\u1ed1i file chuy\u00ean d\u1ee5ng c\u1ee7a Greenplum, gi\u00fap gi\u1ea3i quy\u1ebft tri\u1ec7t \u0111\u1ec3 n\u00fat th\u1eaft c\u1ed5 chai c\u1ee7a Master Node trong l\u1ec7nh `COPY` truy\u1ec1n th\u1ed1ng.\n    \n-   Ho\u1ea1t \u0111\u1ed9ng d\u1ef1a tr\u00ean m\u00f4 h\u00ecnh HTTP Server nh\u1eb9, cho ph\u00e9p **t\u1ea5t c\u1ea3 c\u00e1c Segment \u0111\u1ed3ng lo\u1ea1t k\u1ebft n\u1ed1i song song** \u0111\u1ec3 t\u1ef1 \u0111\u1ed9ng k\u00e9o d\u1eef li\u1ec7u v\u1ec1 ph\u00e2n t\u00e1n.\n    \n-   K\u1ebft h\u1ee3p gi\u1eefa **`gpfdist`** v\u00e0 **`External Tables`** l\u00e0 ti\u00eau chu\u1ea9n v\u00e0ng trong c\u00e1c ki\u1ebfn tr\u00fac ETL hi\u1ec7n \u0111\u1ea1i \u0111\u1ec3 n\u1ea1p h\u00e0ng Terabyte d\u1eef li\u1ec7u v\u00e0o Greenplum v\u1edbi t\u1ed1c \u0111\u1ed9 t\u1ed1i \u0111a c\u1ee7a ph\u1ea7n c\u1ee9ng.\n    \n\n_\u1ede b\u00e0i h\u1ecdc ti\u1ebfp theo (**B\u00e0i h\u1ecdc 22**), ch\u00fang ta s\u1ebd t\u00ecm hi\u1ec3u s\u00e2u h\u01a1n v\u1ec1 c\u00f4ng c\u1ee5 n\u00e0y qua b\u00e0i h\u1ecdc: **External Tables (Readable & Writable): Truy v\u1ea5n tr\u1ef1c ti\u1ebfp file CSV\/Text b\u00ean ngo\u00e0i m\u00e0 kh\u00f4ng c\u1ea7n Import**._\n\nB\u1ea1n c\u00f3 mu\u1ed1n th\u1eed c\u1ea5u h\u00ecnh m\u1ed9t ti\u1ebfn tr\u00ecnh gpfdist k\u00e8m theo t\u00ednh n\u0103ng ghi nh\u1eadn d\u00f2ng l\u1ed7i (Log Errors) \u0111\u1ec3 x\u1eed l\u00fd file CSV b\u1ea9n kh\u00f4ng?","published_at":"2026-10-25T09:47:24.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T11:31:02.000000Z","edited_at":"2026-10-24T08:26:44.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":7,"points":0,"views_count":5,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/c99a0554-17f7-4b20-aeb9-129d3872a087.png","user":{"data":{"id":182732,"url":"https:\/\/viblo.asia\/u\/Hieumn","avatar":"b79a0c92-fb82-49df-bda1-2f51c8e45300.jpg","name":"Nguyen Hoang","username":"Hieumn","followers_count":0,"reputation":2,"posts_count":50,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"cloud-database","name":"cloud database"}]},"commentators":{"data":[]}},{"id":109601,"title":"Greenplum Database B\u00e0i h\u1ecdc 20: L\u1ec7nh COPY trong Greenplum: C\u01a1 ch\u1ebf ho\u1ea1t \u0111\u1ed9ng v\u00e0 gi\u1edbi h\u1ea1n c\u1ee7a vi\u1ec7c n\u1ea1p d\u1eef li\u1ec7u qua Master","slug":"pPLkNQWyJRZ","url":"https:\/\/viblo.asia\/p\/greenplum-database-bai-hoc-20-lenh-copy-trong-greenplum-co-che-hoat-dong-va-gioi-han-cua-viec-nap-du-lieu-qua-master-pPLkNQWyJRZ","user_id":182732,"moderation":null,"transliterated":"greenplum-database-bai-hoc-20-lenh-copy-trong-greenplum-co-che-hoat-dong-va-gioi-han-cua-viec-nap-du-lieu-qua-master","contents_short":"\u1ede B\u00e0i h\u1ecdc 19, ch\u00fang ta \u0111\u00e3 ch\u1ec9 ra r\u1eb1ng vi\u1ec7c s\u1eed d\u1ee5ng c\u00e1c c\u00e2u l\u1ec7nh INSERT INTO \u0111\u01a1n l\u1ebb l\u00e0 \"c\u1ebb th\u00f9\" l\u00e0m ki\u1ec7t qu\u1ec7 t\u00e0i nguy\u00ean c\u1ee7a Master Node v\u00e0 l\u00e0m ngh\u1ebdn m\u1ea1ng Interconnect trong ki\u1ebfn tr\u00fac MPP. V\u1eady c\u00e2u h\u1ecfi \u0111\u1eb7t ra l\u00e0:  C\u00e1ch ti\u00eau chu\u1ea9n \u0111\u1ea7u ti\u00ean \u0111\u1ec3 n\u1ea1p d\u1eef li\u1ec7u h\u00e0ng lo\u1ea1t (Bulk Load) v\u00e0o Greenplum l\u00e0 g\u00ec?\n\nC\u00e2u tr\u1ea3 l\u1eddi ch\u00ednh l\u00e0 l\u1ec7nh COPY (b\u1eaft ngu\u1ed3n t\u1eeb PostgreSQL). Trong b\u00e0i h\u1ecdc n\u00e0y, ch\u00fang ta s\u1ebd m\u1ed5 x\u1ebb c\u01a1 ch\u1ebf ...","contents":"\u1ede B\u00e0i h\u1ecdc 19, ch\u00fang ta \u0111\u00e3 ch\u1ec9 ra r\u1eb1ng vi\u1ec7c s\u1eed d\u1ee5ng c\u00e1c c\u00e2u l\u1ec7nh `INSERT INTO` \u0111\u01a1n l\u1ebb l\u00e0 \"c\u1ebb th\u00f9\" l\u00e0m ki\u1ec7t qu\u1ec7 t\u00e0i nguy\u00ean c\u1ee7a Master Node v\u00e0 l\u00e0m ngh\u1ebdn m\u1ea1ng Interconnect trong ki\u1ebfn tr\u00fac MPP. V\u1eady c\u00e2u h\u1ecfi \u0111\u1eb7t ra l\u00e0:  **C\u00e1ch ti\u00eau chu\u1ea9n \u0111\u1ea7u ti\u00ean \u0111\u1ec3 n\u1ea1p d\u1eef li\u1ec7u h\u00e0ng lo\u1ea1t (Bulk Load) v\u00e0o Greenplum l\u00e0 g\u00ec?**\n\nC\u00e2u tr\u1ea3 l\u1eddi ch\u00ednh l\u00e0 l\u1ec7nh **`COPY`** (b\u1eaft ngu\u1ed3n t\u1eeb PostgreSQL). Trong b\u00e0i h\u1ecdc n\u00e0y, ch\u00fang ta s\u1ebd m\u1ed5 x\u1ebb c\u01a1 ch\u1ebf ho\u1ea1t \u0111\u1ed9ng b\u00ean d\u01b0\u1edbi c\u1ee7a l\u1ec7nh `COPY`, hi\u1ec3u r\u00f5 n\u00f3 gi\u1ea3i quy\u1ebft b\u00e0i to\u00e1n t\u1ed1c \u0111\u1ed9 ra sao, \u0111\u1ed3ng th\u1eddi nh\u1eadn di\u1ec7n nh\u1eefng gi\u1edbi h\u1ea1n ph\u1ea7n c\u1ee9ng quan tr\u1ecdng khi n\u1ea1p d\u1eef li\u1ec7u qua Master Node.\n\n## 1. B\u1ea3n ch\u1ea5t ho\u1ea1t \u0111\u1ed9ng c\u1ee7a l\u1ec7nh `COPY`\n\nL\u1ec7nh `COPY` (v\u00ed d\u1ee5:  `COPY table_name FROM STDIN WITH CSV` ho\u1eb7c `COPY table_name FROM '\/path\/to\/file.csv'`) l\u00e0 c\u00e2u l\u1ec7nh t\u1ed1i \u01b0u h\u00f3a chuy\u00ean d\u1ee5ng c\u1ee7a h\u1ec7 sinh th\u00e1i PostgreSQL \u0111\u1ec3 chuy\u1ec3n d\u1eef li\u1ec7u h\u00e0ng lo\u1ea1t gi\u1eefa b\u1ea3ng c\u01a1 s\u1edf d\u1eef li\u1ec7u v\u00e0 t\u1ec7p tin v\u0103n b\u1ea3n (CSV, Text, Binary).\n\n### \u0110i\u1ec3m kh\u00e1c bi\u1ec7t c\u1ed1t l\u00f5i so v\u1edbi `INSERT`:\n\n-   **B\u1ecf qua t\u1ea7ng ph\u00e2n t\u00edch c\u00fa ph\u00e1p l\u1eb7p l\u1ea1i:** Thay v\u00ec ph\u1ea3i bi\u00ean d\u1ecbch t\u1eebng c\u00e2u l\u1ec7nh SQL `INSERT` ri\u00eang bi\u1ec7t, l\u1ec7nh `COPY` \u0111\u1ecdc nguy\u00ean m\u1ed9t lu\u1ed3ng d\u1eef li\u1ec7u th\u00f4 (raw data stream), ph\u00e2n t\u00edch \u0111\u1ecbnh d\u1ea1ng ph\u00e2n c\u00e1ch (delimiter) theo t\u1eebng block l\u1edbn.\n    \n-   **Gi\u1ea3m thi\u1ec3u chi ph\u00ed giao d\u1ecbch (Transaction Overhead):** To\u00e0n b\u1ed9 t\u1ec7p d\u1eef li\u1ec7u l\u1edbn \u0111\u01b0\u1ee3c x\u1eed l\u00fd g\u1ecdn trong m\u1ed9t phi\u00ean giao d\u1ecbch duy nh\u1ea5t thay v\u00ec h\u00e0ng tri\u1ec7u giao d\u1ecbch \u0111\u1ed9c l\u1eadp.\n    \n-   **T\u1ed1c \u0111\u1ed9 v\u01b0\u1ee3t tr\u1ed9i:** Gi\u00fap t\u0103ng t\u1ed1c \u0111\u1ed9 n\u1ea1p d\u1eef li\u1ec7u l\u00ean g\u1ea5p **10 \u0111\u1ebfn 50 l\u1ea7n** so v\u1edbi vi\u1ec7c d\u00f9ng v\u00f2ng l\u1eb7p `INSERT`.\n    \n\n## 2. Gi\u1ea3i ph\u1eabu lu\u1ed3ng th\u1ef1c thi l\u1ec7nh `COPY` qua Master Node\n\nD\u00f9 Greenplum l\u00e0 m\u1ed9t h\u1ec7 th\u1ed1ng ph\u00e2n t\u00e1n, khi b\u1ea1n ch\u1ea1y m\u1ed9t l\u1ec7nh `COPY` ti\u00eau chu\u1ea9n t\u1eeb m\u00e1y Client \u0111\u1ea9y v\u00e0o c\u01a1 s\u1edf d\u1eef li\u1ec7u, lu\u1ed3ng d\u1eef li\u1ec7u v\u1eabn ph\u1ea3i tu\u00e2n theo m\u00f4 h\u00ecnh \u0111i\u1ec1u ph\u1ed1i qua Master:\n\n```\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502               LU\u1ed2NG TH\u1ef0C THI L\u1ec6NH COPY TRUY\u1ec0N TH\u1ed0NG QUA MASTER          \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                            \u2502                        \u2502\n     [ Client Machine ] \u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u25ba [ Master Node (QD) ] \u2500\u2500\u2500 (Ph\u00e2n ph\u1ed1i d\u1eef li\u1ec7u)\n                                         \u2502\n                 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n                 \u25bc                                               \u25bc\n         [ Segment Host 1 ]                              [ Segment Host 2 ]\n         \u2022 Nh\u1eadn d\u00f2ng d\u1eef li\u1ec7u qua Interconnect            \u2022 Nh\u1eadn d\u00f2ng d\u1eef li\u1ec7u qua Interconnect\n         \u2022 B\u0103m Hash theo Distribution Key                \u2022 B\u0103m Hash theo Distribution Key\n         \u2022 Ghi xu\u1ed1ng \u0111\u0129a l\u01b0u tr\u1eef                         \u2022 Ghi xu\u1ed1ng \u0111\u0129a l\u01b0u tr\u1eef\n\n```\n\n### C\u00e1c b\u01b0\u1edbc di\u1ec5n ra b\u00ean trong:\n\n1.  **Ti\u1ebfp nh\u1eadn lu\u1ed3ng d\u1eef li\u1ec7u:** Master Node (trong vai tr\u00f2 Query Dispatcher - QD) nh\u1eadn t\u1ec7p d\u1eef li\u1ec7u t\u1eeb Client.\n    \n2.  **Ph\u00e2n t\u00edch v\u00e0 \u0110\u1ecbnh tuy\u1ebfn (Parsing & Routing):** Master \u0111\u1ecdc t\u1eebng d\u00f2ng d\u1eef li\u1ec7u, tr\u00edch xu\u1ea5t gi\u00e1 tr\u1ecb t\u1ea1i c\u1ed9t l\u00e0m **Distribution Key** (`DISTRIBUTED BY`), sau \u0111\u00f3 \u0111\u01b0a qua h\u00e0m b\u0103m (Hash Function) \u0111\u1ec3 x\u00e1c \u0111\u1ecbnh xem d\u00f2ng \u0111\u00f3 thu\u1ed9c v\u1ec1 Segment n\u00e0o.\n    \n3.  **Chuy\u1ec3n t\u1ea3i qua Interconnect:** Master \u0111\u1ea9y c\u00e1c g\u00f3i d\u1eef li\u1ec7u n\u00e0y th\u00f4ng qua m\u1ea1ng n\u1ed9i b\u1ed9 Interconnect xu\u1ed1ng c\u00e1c ti\u1ebfn tr\u00ecnh th\u1ef1c thi (`QE`) tr\u00ean t\u1eebng Segment t\u01b0\u01a1ng \u1ee9ng.\n    \n4.  **Ghi xu\u1ed1ng \u0111\u0129a:** C\u00e1c Segment nh\u1eadn d\u1eef li\u1ec7u v\u00e0 ti\u1ebfn h\u00e0nh ghi tu\u1ea7n t\u1ef1 v\u00e0o c\u00e1c b\u1ea3ng l\u01b0u tr\u1eef (Heap ho\u1eb7c Append-Optimized).\n    \n\n## 3. Gi\u1edbi h\u1ea1n ch\u00ed m\u1ea1ng: \"N\u00fat th\u1eaft c\u1ed5 chai\" Master Node c\u1ee7a l\u1ec7nh `COPY` truy\u1ec1n th\u1ed1ng\n\nM\u1eb7c d\u00f9 l\u1ec7nh `COPY` nhanh h\u01a1n `INSERT` r\u1ea5t nhi\u1ec1u, nh\u01b0ng khi b\u1ea1n c\u1ea7n n\u1ea1p c\u00e1c t\u1ec7p d\u1eef li\u1ec7u kh\u1ed5ng l\u1ed3 (v\u00e0i ch\u1ee5c \u0111\u1ebfn h\u00e0ng tr\u0103m Gigabyte) trong c\u00e1c h\u1ec7 th\u1ed1ng Big Data, l\u1ec7nh `COPY` truy\u1ec1n th\u1ed1ng b\u1eaft \u0111\u1ea7u b\u1ed9c l\u1ed9 **3 \u0111i\u1ec3m y\u1ebfu c\u1ed1t l\u00f5i**:\n\n### 3.1. Master Node tr\u1edf th\u00e0nh \u1ed1ng h\u00fat c\u1ed5 chai (Master Bottleneck)\n\n-   To\u00e0n b\u1ed9 t\u1ec7p d\u1eef li\u1ec7u t\u1eeb m\u00e1y Client **b\u1eaft bu\u1ed9c ph\u1ea3i ch\u1ea1y qua m\u1ed9t m\u00ecnh Master Node**.\n    \n-   Master kh\u00f4ng ch\u1ec9 ph\u1ea3i l\u01b0u tr\u1eef phi\u00ean l\u00e0m vi\u1ec7c, m\u00e0 c\u00f2n ph\u1ea3i g\u00e1nh th\u00eam to\u00e0n b\u1ed9 c\u00f4ng vi\u1ec7c ph\u00e2n t\u00edch \u0111\u1ecbnh d\u1ea1ng (Parsing), t\u00ednh to\u00e1n h\u00e0m b\u0103m Hash cho t\u1eebng d\u00f2ng, v\u00e0 \u0111i\u1ec1u ph\u1ed1i g\u1eedi \u0111i qua m\u1ea1ng.\n    \n-   Khi t\u1ec7p d\u1eef li\u1ec7u qu\u00e1 l\u1edbn (v\u00ed d\u1ee5 50 GB), CPU v\u00e0 card m\u1ea1ng c\u1ee7a m\u00e1y ch\u1ee7 Master s\u1ebd b\u1ecb b\u00e3o h\u00f2a 100%, trong khi t\u00e0i nguy\u00ean ph\u1ea7n c\u1ee9ng c\u1ee7a h\u00e0ng ch\u1ee5c m\u00e1y ch\u1ee7 Segment b\u00ean d\u01b0\u1edbi l\u1ea1i ng\u1ed3i ch\u01a1i x\u01a1i n\u01b0\u1edbc v\u00ec ph\u1ea3i ch\u1edd Master ph\u00e2n ph\u1ed1i d\u1eef li\u1ec7u t\u1edbi!\n    \n\n### 3.2. Gi\u1edbi h\u1ea1n \u0111\u01b0\u1eddng truy\u1ec1n m\u1ea1ng Client - Server\n\n-   N\u1ebfu \u1ee9ng d\u1ee5ng ETL c\u1ee7a b\u1ea1n ch\u1ea1y \u1edf m\u1ed9t m\u00e1y ch\u1ee7 b\u00ean ngo\u00e0i, vi\u1ec7c truy\u1ec1n t\u1ea3i m\u1ed9t t\u1ec7p d\u1eef li\u1ec7u kh\u1ed5ng l\u1ed3 qua m\u1ed9t lu\u1ed3ng m\u1ea1ng duy nh\u1ea5t c\u1eafm th\u1eb3ng v\u00e0o c\u1ed5ng `5432` c\u1ee7a Master r\u1ea5t d\u1ec5 b\u1ecb \u0111\u1ee9t qu\u00e3ng (Timeout) ho\u1eb7c b\u1ecb ngh\u1ebdn b\u0103ng th\u00f4ng m\u1ea1ng ngo\u1ea1i vi (Public\/LAN Network).\n    \n\n## 4. Khi n\u00e0o N\u00caN v\u00e0 KH\u00d4NG N\u00caN d\u00f9ng l\u1ec7nh `COPY`?\n\n-   **N\u00caN D\u00d9NG khi:**\n    \n    -   Dung l\u01b0\u1ee3ng t\u1ec7p d\u1eef li\u1ec7u \u1edf m\u1ee9c nh\u1ecf v\u00e0 trung b\u00ecnh (d\u01b0\u1edbi v\u00e0i Gigabyte).\n        \n    -   N\u1ea1p d\u1eef li\u1ec7u c\u1ea5u h\u00ecnh, b\u1ea3ng danh m\u1ee5c (Dimension tables) ho\u1eb7c c\u00e1c file d\u1eef li\u1ec7u c\u1ee5c b\u1ed9 n\u1eb1m s\u1eb5n tr\u00ean m\u00e1y ch\u1ee7 Master (s\u1eed d\u1ee5ng c\u00fa ph\u00e1p `COPY table FROM STDIN` ho\u1eb7c `COPY table FROM '\/path\/on\/master\/file.csv'`).\n        \n-   **KH\u00d4NG N\u00caN D\u00d9NG khi:**\n    \n    -   B\u1ea1n c\u1ea7n n\u1ea1p c\u00e1c t\u1ec7p d\u1eef li\u1ec7u kh\u1ed5ng l\u1ed3 h\u00e0ng ch\u1ee5c\/h\u00e0ng tr\u0103m Terabyte t\u1eeb h\u1ec7 th\u1ed1ng b\u00ean ngo\u00e0i ho\u1eb7c t\u1eeb Cloud Storage (AWS S3, MinIO, HDFS).\n        \n    -   \u0110\u1ed1i v\u1edbi c\u00e1c t\u00e1c v\u1ee5 Big Data quy m\u00f4 l\u1edbn n\u00e0y, l\u1ec7nh `COPY` truy\u1ec1n th\u1ed1ng qua Master s\u1ebd th\u1ea5t b\u1ea1i ho\u1eb7c ch\u1ea1y c\u1ef1c k\u1ef3 ch\u1eadm. \u0110\u00f3 l\u00e0 l\u00fac ch\u00fang ta ph\u1ea3i g\u1ecdi t\u00ean c\u00f4ng c\u1ee5 chuy\u00ean d\u1ee5ng:  **`gpfdist`** v\u00e0 **`External Tables`** (s\u1ebd \u0111\u01b0\u1ee3c h\u1ecdc \u1edf B\u00e0i 21 v\u00e0 22).\n        \n\n## T\u00f3m t\u1eaft B\u00e0i h\u1ecdc 20\n\n-   L\u1ec7nh `COPY` gi\u00fap t\u0103ng t\u1ed1c \u0111\u1ed9 n\u1ea1p d\u1eef li\u1ec7u l\u00ean g\u1ea5p nhi\u1ec1u l\u1ea7n so v\u1edbi `INSERT` nh\u1edd x\u1eed l\u00fd theo l\u00f4 d\u00f2ng (batch) v\u00e0 gi\u1ea3m thi\u1ec3u chi ph\u00ed ph\u00e2n t\u00edch c\u00fa ph\u00e1p l\u1eb7p l\u1ea1i.\n    \n-   V\u1ec1 m\u1eb7t ki\u1ebfn tr\u00fac, l\u1ec7nh `COPY` truy\u1ec1n th\u1ed1ng v\u1eabn \u0111\u1ea9y to\u00e0n b\u1ed9 d\u1eef li\u1ec7u \u0111i qua Master Node \u0111\u1ec3 t\u00ednh to\u00e1n h\u00e0m b\u0103m v\u00e0 ph\u00e2n ph\u1ed1i xu\u1ed1ng c\u00e1c Segment.\n    \n-   V\u1edbi c\u00e1c t\u1ec7p d\u1eef li\u1ec7u kh\u1ed5ng l\u1ed3, Master Node s\u1ebd tr\u1edf th\u00e0nh n\u00fat th\u1eaft c\u1ed5 chai ph\u1ea7n c\u1ee9ng, \u0111\u00f2i h\u1ecfi c\u00e1c gi\u1ea3i ph\u00e1p n\u1ea1p d\u1eef li\u1ec7u song song tr\u1ef1c ti\u1ebfp kh\u00f4ng qua Master.\n    \n\n_\u1ede b\u00e0i h\u1ecdc ti\u1ebfp theo (**B\u00e0i h\u1ecdc 21**), ch\u00fang ta s\u1ebd gi\u1ea3i quy\u1ebft tri\u1ec7t \u0111\u1ec3 n\u00fat th\u1eaft c\u1ed5 chai c\u1ee7a Master b\u1eb1ng c\u00f4ng c\u1ee5 t\u1ed1i th\u01b0\u1ee3ng: **Ki\u1ebfn tr\u00fac `gpfdist`: Ph\u00e1 v\u1ee1 n\u00fat th\u1eaft c\u1ed5 chai \u1edf Master b\u1eb1ng c\u00e1ch n\u1ea1p song song tr\u1ef1c ti\u1ebfp v\u00e0o c\u00e1c Segment**._\n\nB\u1ea1n c\u00f3 mu\u1ed1n th\u1eed vi\u1ebft m\u1ed9t c\u00e2u l\u1ec7nh `COPY` t\u1ed1i \u01b0u k\u00e8m theo c\u1ea5u h\u00ecnh ph\u00e2n c\u00e1ch d\u1eef li\u1ec7u (delimiter) \u0111\u1ec3 n\u1ea1p file CSV v\u00e0o b\u1ea3ng ph\u00e2n t\u00e1n tr\u00ean Greenplum kh\u00f4ng?","published_at":"2026-10-25T09:47:15.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T15:52:02.000000Z","edited_at":"2026-10-24T08:26:04.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":7,"points":0,"views_count":7,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/2e015342-b77a-41e3-895f-4e41944f49e3.png","user":{"data":{"id":182732,"url":"https:\/\/viblo.asia\/u\/Hieumn","avatar":"b79a0c92-fb82-49df-bda1-2f51c8e45300.jpg","name":"Nguyen Hoang","username":"Hieumn","followers_count":0,"reputation":2,"posts_count":50,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"cloud-database","name":"cloud database"}]},"commentators":{"data":[]}},{"id":108860,"title":"Trino SQL B\u00e0i h\u1ecdc 39: \u0110\u1ecdc hi\u1ec3u v\u00e0 ph\u00e2n t\u00edch k\u1ebf ho\u1ea1ch th\u1ef1c thi (EXPLAIN)","slug":"OQJwzOab4MP","url":"https:\/\/viblo.asia\/p\/trino-sql-bai-hoc-39-doc-hieu-va-phan-tich-ke-hoach-thuc-thi-explain-OQJwzOab4MP","user_id":184792,"moderation":null,"transliterated":"trino-sql-bai-hoc-39-doc-hieu-va-phan-tich-ke-hoach-thuc-thi-explain","contents_short":"M\u1ee5c ti\u00eau b\u00e0i h\u1ecdc:\n\n-   Hi\u1ec3u b\u1ea3n ch\u1ea5t \u0111\u1ecbnh tuy\u1ebfn c\u1ee7a Trino: SQL l\u00e0 ng\u00f4n ng\u1eef khai b\u00e1o (Declarative), Engine m\u1edbi l\u00e0 ng\u01b0\u1eddi quy\u1ebft \u0111\u1ecbnh c\u00e1ch th\u1ef1c thi (Imperative).\n\n-   S\u1eed d\u1ee5ng EXPLAIN \u0111\u1ec3 xem K\u1ebf ho\u1ea1ch logic (Logical Plan).\n\n-   S\u1eed d\u1ee5ng EXPLAIN (TYPE DISTRIBUTED) \u0111\u1ec3 hi\u1ec3u c\u00e1ch Trino chia nh\u1ecf c\u00f4ng vi\u1ec7c cho c\u00e1c Worker.\n\n-   D\u00f9ng EXPLAIN ANALYZE \u0111\u1ec3 \"kh\u00e1m nghi\u1ec7m t\u1eed thi\" m\u1ed9t truy v\u1ea5n ch\u1eadm v\u00e0 t\u00ecm ra th\u1eaft c\u1ed5 ...","contents":"**M\u1ee5c ti\u00eau b\u00e0i h\u1ecdc:**\n\n-   Hi\u1ec3u b\u1ea3n ch\u1ea5t \u0111\u1ecbnh tuy\u1ebfn c\u1ee7a Trino: SQL l\u00e0 ng\u00f4n ng\u1eef khai b\u00e1o (Declarative), Engine m\u1edbi l\u00e0 ng\u01b0\u1eddi quy\u1ebft \u0111\u1ecbnh c\u00e1ch th\u1ef1c thi (Imperative).\n    \n-   S\u1eed d\u1ee5ng `EXPLAIN` \u0111\u1ec3 xem K\u1ebf ho\u1ea1ch logic (Logical Plan).\n    \n-   S\u1eed d\u1ee5ng `EXPLAIN (TYPE DISTRIBUTED)` \u0111\u1ec3 hi\u1ec3u c\u00e1ch Trino chia nh\u1ecf c\u00f4ng vi\u1ec7c cho c\u00e1c Worker.\n    \n-   D\u00f9ng `EXPLAIN ANALYZE` \u0111\u1ec3 \"kh\u00e1m nghi\u1ec7m t\u1eed thi\" m\u1ed9t truy v\u1ea5n ch\u1eadm v\u00e0 t\u00ecm ra th\u1eaft c\u1ed5 chai (Bottleneck).\n    \n\n## 1. T\u1ea1i sao c\u00f9ng m\u1ed9t c\u00e2u l\u1ec7nh, l\u00fac ch\u1ea1y nhanh l\u00fac ch\u1ea1y ch\u1eadm?\n\nKhi b\u1ea1n vi\u1ebft SQL, b\u1ea1n \u0111ang n\u00f3i cho Trino bi\u1ebft **\"B\u1ea1n mu\u1ed1n k\u1ebft qu\u1ea3 g\u00ec\"** (What), ch\u1ee9 kh\u00f4ng ph\u1ea3i **\"L\u00e0m nh\u01b0 th\u1ebf n\u00e0o\"** (How).\n\nTrino c\u00f3 m\u1ed9t b\u1ed9 n\u00e3o g\u1ecdi l\u00e0 **Cost-Based Optimizer (CBO)**. Khi nh\u1eadn c\u00e2u l\u1ec7nh c\u1ee7a b\u1ea1n, CBO s\u1ebd ph\u00e2n t\u00edch si\u00eau d\u1eef li\u1ec7u (th\u1ed1ng k\u00ea s\u1ed1 d\u00f2ng, dung l\u01b0\u1ee3ng b\u1ea3ng) v\u00e0 v\u1ea1ch ra h\u00e0ng ch\u1ee5c l\u1ed9 tr\u00ecnh kh\u1ea3 thi. Cu\u1ed1i c\u00f9ng, n\u00f3 ch\u1ecdn ra l\u1ed9 tr\u00ecnh (Query Plan) t\u1ed1n \u00edt CPU v\u00e0 RAM nh\u1ea5t \u0111\u1ec3 ch\u1ea1y. \u0110\u00f4i khi CBO \u0111o\u00e1n sai, ho\u1eb7c do b\u1ea1n vi\u1ebft SQL ch\u01b0a chu\u1ea9n (nh\u01b0 l\u1ea1m d\u1ee5ng Correlated Subquery \u1edf B\u00e0i 37), d\u1eabn \u0111\u1ebfn Trino ch\u1ecdn m\u1ed9t l\u1ed9 tr\u00ecnh th\u1ea3m h\u1ecda. `EXPLAIN` l\u00e0 c\u00f4ng c\u1ee5 \u0111\u1ec3 b\u1ea1n nh\u00ecn th\u1ea5u b\u1ed9 n\u00e3o n\u00e0y.\n\n## 2. EXPLAIN: Xem k\u1ebf ho\u1ea1ch Logic (Logical Plan)\n\nB\u1eb1ng c\u00e1ch \u0111\u1eb7t ch\u1eef `EXPLAIN` tr\u01b0\u1edbc b\u1ea5t k\u1ef3 c\u00e2u `SELECT` n\u00e0o, Trino s\u1ebd **kh\u00f4ng ch\u1ea1y** c\u00e2u l\u1ec7nh \u0111\u00f3, m\u00e0 ch\u1ec9 in ra b\u1ea3n v\u1ebd thi\u1ebft k\u1ebf (Blueprint) c\u1ee7a n\u00f3.\n\nSQL\n\n```\nEXPLAIN \nSELECT c.mktsegment, SUM(o.totalprice)\nFROM tpch.tiny.customer AS c\nJOIN tpch.tiny.orders AS o ON c.custkey = o.custkey\nGROUP BY c.mktsegment;\n\n```\n\n**C\u00e1ch \u0111\u1ecdc K\u1ebf ho\u1ea1ch Logic:** Trino in ra m\u1ed9t c\u00e1i c\u00e2y (Tree). B\u1ea1n ph\u1ea3i \u0111\u1ecdc t\u1eeb **d\u01b0\u1edbi c\u00f9ng l\u00ean tr\u00ean c\u00f9ng** (Bottom-up).\n\n1.  **TableScan:** \u1ede d\u01b0\u1edbi \u0111\u00e1y, Trino s\u1ebd qu\u00e9t b\u1ea3ng (qu\u00e9t b\u1ea3ng `orders` v\u00e0 b\u1ea3ng `customer`).\n    \n2.  **Filter\/Project:** L\u1ecdc d\u1eef li\u1ec7u v\u00e0 ch\u1ecdn c\u00e1c c\u1ed9t c\u1ea7n thi\u1ebft.\n    \n3.  **InnerJoin:** Trino quy\u1ebft \u0111\u1ecbnh thu\u1eadt to\u00e1n Join (v\u00ed d\u1ee5: Hash Join hay Nested Loop).\n    \n4.  **Aggregate:** Gom nh\u00f3m v\u00e0 t\u00ednh to\u00e1n (`SUM`, `GROUP BY`).\n    \n5.  **Output:** Tr\u1ea3 k\u1ebft qu\u1ea3 v\u1ec1 m\u00e0n h\u00ecnh.\n    \n\n## 3. EXPLAIN (TYPE DISTRIBUTED): B\u1ea3n \u0111\u1ed3 t\u00e1c chi\u1ebfn ph\u00e2n t\u00e1n\n\nK\u1ebf ho\u1ea1ch logic ch\u1ec9 l\u00e0 l\u00fd thuy\u1ebft. Tr\u00ean th\u1ef1c t\u1ebf, Trino l\u00e0 h\u1ec7 th\u1ed1ng ph\u00e2n t\u00e1n v\u1edbi h\u00e0ng ch\u1ee5c Worker Node. K\u1ebf ho\u1ea1ch logic s\u1ebd \u0111\u01b0\u1ee3c ch\u1eb7t ra th\u00e0nh nhi\u1ec1u **Fragments** (M\u1ea3nh v\u1ee1\/Giai \u0111o\u1ea1n).\n\nSQL\n\n```\nEXPLAIN (TYPE DISTRIBUTED) \nSELECT ...\n\n```\n\n**C\u00e1c kh\u00e1i ni\u1ec7m c\u1ed1t l\u00f5i trong Distributed Plan:**\n\n-   **Fragment:** M\u1ed7i Fragment l\u00e0 m\u1ed9t nhi\u1ec7m v\u1ee5 \u0111\u1ed9c l\u1eadp \u0111\u01b0\u1ee3c giao cho m\u1ed9t nh\u00f3m Worker ch\u1ea1y song song.\n    \n-   **Exchange (Trao \u0111\u1ed5i d\u1eef li\u1ec7u):** Khi Fragment 1 l\u00e0m xong, n\u00f3 ph\u1ea3i n\u00e9m d\u1eef li\u1ec7u cho Fragment 2. Qu\u00e1 tr\u00ecnh bay qua l\u1ea1i tr\u00ean m\u1ea1ng Network n\u00e0y g\u1ecdi l\u00e0 Exchange.\n    \n    -   _Local Exchange:_ D\u1eef li\u1ec7u trao \u0111\u1ed5i ngay trong RAM c\u1ee7a c\u00f9ng m\u1ed9t m\u00e1y (R\u1ea5t nhanh).\n        \n    -   _Remote Exchange:_ M\u00e1y Worker A ph\u1ea3i g\u1eedi d\u1eef li\u1ec7u qua c\u00e1p m\u1ea1ng cho m\u00e1y Worker B (R\u1ea5t ch\u1eadm, t\u1ed1n I\/O).\n        \n\n_G\u00f3c nh\u00ecn K\u1ef9 s\u01b0:_ M\u1ed9t Query Plan t\u1ed1t l\u00e0 m\u1ed9t Plan h\u1ea1n ch\u1ebf t\u1ed1i \u0111a c\u00e1c `Remote Exchange` kh\u1ed5ng l\u1ed3.\n\n## 4. EXPLAIN ANALYZE: \"Kh\u00e1m nghi\u1ec7m t\u1eed thi\" truy v\u1ea5n th\u1ef1c t\u1ebf\n\n`EXPLAIN` ch\u1ec9 l\u00e0 s\u1ef1 ph\u1ecfng \u0111o\u00e1n c\u1ee7a Trino tr\u01b0\u1edbc khi ch\u1ea1y. \u0110\u00f4i khi Trino \u0111o\u00e1n b\u1ea3ng n\u00e0y ch\u1ec9 c\u00f3 1000 d\u00f2ng, nh\u01b0ng th\u1ef1c t\u1ebf n\u00f3 c\u00f3 1 t\u1ef7 d\u00f2ng.\n\n\u0110\u1ec3 bi\u1ebft ch\u00ednh x\u00e1c chuy\u1ec7n g\u00ec \u0111\u00e3 x\u1ea3y ra, b\u1ea1n d\u00f9ng `EXPLAIN ANALYZE`. **L\u01b0u \u00fd:** L\u1ec7nh n\u00e0y s\u1ebd **th\u1ef1c s\u1ef1 ch\u1ea1y** c\u00e2u truy v\u1ea5n c\u1ee7a b\u1ea1n \u0111\u1ebfn khi ho\u00e0n t\u1ea5t, sau \u0111\u00f3 n\u00f3 m\u1edbi nh\u1ea3 ra b\u00e1o c\u00e1o chi ti\u1ebft v\u1ec1 CPU, Memory v\u00e0 th\u1eddi gian c\u1ee7a t\u1eebng Node.\n\nSQL\n\n```\nEXPLAIN ANALYZE \nSELECT ...\n\n```\n\n**Nh\u1eefng ch\u1ec9 s\u1ed1 v\u00e0ng c\u1ea7n ch\u00fa \u00fd trong k\u1ebft qu\u1ea3:**\n\n-   **CPU time:** Node n\u00e0o ti\u00eau t\u1ed1n nhi\u1ec1u th\u1eddi gian CPU nh\u1ea5t? (Th\u01b0\u1eddng l\u00e0 c\u00e1c node `Aggregate` c\u00f3 `GROUP BY` qu\u00e1 nhi\u1ec1u c\u1ed9t, ho\u1eb7c d\u00f9ng `CROSS JOIN`).\n    \n-   **Scheduled time:** Th\u1eddi gian th\u1ef1c t\u1ebf ch\u1edd \u0111\u1ee3i.\n    \n-   **Input rows:** S\u1ed1 d\u00f2ng d\u1eef li\u1ec7u b\u01a1m v\u00e0o. N\u1ebfu b\u1ea1n th\u1ea5y Input l\u00e0 1 t\u1ef7 d\u00f2ng, nh\u01b0ng Output ch\u1ec9 c\u00f3 10 d\u00f2ng, ngh\u0129a l\u00e0 b\u1ea1n \u0111\u00e3 qu\u00ean l\u1ecdc `WHERE` t\u1eeb s\u1edbm, b\u1eaft h\u1ec7 th\u1ed1ng ph\u1ea3i t\u00ednh to\u00e1n r\u00e1c.\n    \n-   **Data Skew (L\u1ec7ch d\u1eef li\u1ec7u):** Trong EXPLAIN ANALYZE, Trino s\u1ebd hi\u1ec3n th\u1ecb s\u1ef1 ph\u00e2n ph\u1ed1i d\u1eef li\u1ec7u. N\u1ebfu b\u1ea1n th\u1ea5y m\u1ed9t Worker x\u1eed l\u00fd 99% d\u1eef li\u1ec7u, c\u00e1c Worker kh\u00e1c ng\u1ed3i ch\u01a1i r\u1ea3nh r\u1ed7i (0%), \u0111\u00f3 l\u00e0 hi\u1ec7n t\u01b0\u1ee3ng Data Skew. C\u00e1ch gi\u1ea3i quy\u1ebft l\u00e0 c\u1ea5u h\u00ecnh l\u1ea1i thu\u1eadt to\u00e1n Hashing ho\u1eb7c ph\u00e2n m\u1ea3nh l\u1ea1i Partition.\n    \n\n## 5. D\u1ea5u hi\u1ec7u nh\u1eadn bi\u1ebft \"B\u00e1o \u0111\u1ed9ng \u0111\u1ecf\" trong Query Plan\n\nKhi \u0111\u1ecdc `EXPLAIN`, n\u1ebfu b\u1ea1n th\u1ea5y c\u00e1c t\u1eeb kh\u00f3a sau, h\u00e3y c\u1ea9n th\u1eadn v\u00e0 t\u00ecm c\u00e1ch vi\u1ebft l\u1ea1i SQL:\n\n1.  **NestedLoopJoin:** Nh\u01b0 \u0111\u00e3 \u0111\u1ec1 c\u1eadp \u1edf B\u00e0i 24, \u0111\u00e2y l\u00e0 th\u1ea3m h\u1ecda. Trino \u0111ang qu\u00e9t t\u1eebng d\u00f2ng ch\u00e9o nhau do b\u1ea1n d\u00f9ng Non-Equi JOIN m\u00e0 thi\u1ebfu m\u1ecf neo `=`.\n    \n2.  **CrossJoinNode:** D\u1eef li\u1ec7u b\u1ecb b\u00f9ng n\u1ed5 (Cartesian Product - B\u00e0i 23).\n    \n3.  **TableScan (Full) tr\u00ean b\u1ea3ng kh\u1ed5ng l\u1ed3:** Trino \u0111ang qu\u00e9t to\u00e0n b\u1ed9 d\u1eef li\u1ec7u l\u1ecbch s\u1eed thay v\u00ec ch\u1ec9 qu\u00e9t ng\u00e0y hi\u1ec7n t\u1ea1i do b\u1ea1n thi\u1ebfu \u0111i\u1ec1u ki\u1ec7n gi\u1edbi h\u1ea1n Partition (nh\u01b0 `WHERE ds = '2023-10-10'`).","published_at":"2026-10-25T09:45:19.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T17:00:31.000000Z","edited_at":"2026-10-11T15:22:38.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":5,"points":0,"views_count":13,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/13123e41-d492-41be-95a7-d1344102da89.png","user":{"data":{"id":184792,"url":"https:\/\/viblo.asia\/u\/nhh","avatar":"81df63c2-e6d9-43a9-85a4-8e807f120997.jpg","name":"Nguy\u1ec5n Huy Ho\u00e0ng","username":"nhh","followers_count":12,"reputation":132,"posts_count":183,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"cac-cau-lenh-trong-ms-sql-server","name":"C\u00e1c C\u00e2u L\u1ec7nh Trong MS SQL Server"}]},"commentators":{"data":[]}},{"id":108859,"title":"Trino SQL B\u00e0i h\u1ecdc 38: K\u1ef9 thu\u1eadt xoay tr\u1ee5c d\u1eef li\u1ec7u (Pivot v\u00e0 Unpivot) trong Trino","slug":"oW4oejnlLml","url":"https:\/\/viblo.asia\/p\/trino-sql-bai-hoc-38-ky-thuat-xoay-truc-du-lieu-pivot-va-unpivot-trong-trino-oW4oejnlLml","user_id":184792,"moderation":null,"transliterated":"trino-sql-bai-hoc-38-ky-thuat-xoay-truc-du-lieu-pivot-va-unpivot-trong-trino","contents_short":"M\u1ee5c ti\u00eau b\u00e0i h\u1ecdc:\n\n-   Ph\u00e2n bi\u1ec7t c\u1ea5u tr\u00fac d\u1eef li\u1ec7u d\u1ea1ng D\u00e0i (Long Format) v\u00e0 d\u1ea1ng R\u1ed9ng (Wide Format).\n\n-   Hi\u1ec3u l\u00fd do t\u1ea1i sao Trino kh\u00f4ng h\u1ed7 tr\u1ee3 t\u1eeb kh\u00f3a PIVOT \/ UNPIVOT nguy\u00ean b\u1ea3n v\u00e0 c\u00e1ch gi\u1ea3i quy\u1ebft chu\u1ea9n ANSI SQL.\n\n-   L\u00e0m ch\u1ee7 k\u1ef9 thu\u1eadt T\u1ed5ng h\u1ee3p c\u00f3 \u0111i\u1ec1u ki\u1ec7n (Conditional Aggregation) \u0111\u1ec3 bi\u1ebfn D\u00f2ng th\u00e0nh C\u1ed9t (Pivot).\n\n-   V\u1eadn d\u1ee5ng k\u1ef9 thu\u1eadt gh\u00e9p m\u1ea3ng CROSS JOIN UNNEST si\u00eau t\u1ed1c \u0111\u1ec3 bi\u1ebfn C\u1ed9t th\u00e0nh D\u00f2n...","contents":"**M\u1ee5c ti\u00eau b\u00e0i h\u1ecdc:**\n\n-   Ph\u00e2n bi\u1ec7t c\u1ea5u tr\u00fac d\u1eef li\u1ec7u d\u1ea1ng D\u00e0i (Long Format) v\u00e0 d\u1ea1ng R\u1ed9ng (Wide Format).\n    \n-   Hi\u1ec3u l\u00fd do t\u1ea1i sao Trino kh\u00f4ng h\u1ed7 tr\u1ee3 t\u1eeb kh\u00f3a `PIVOT` \/ `UNPIVOT` nguy\u00ean b\u1ea3n v\u00e0 c\u00e1ch gi\u1ea3i quy\u1ebft chu\u1ea9n ANSI SQL.\n    \n-   L\u00e0m ch\u1ee7 k\u1ef9 thu\u1eadt T\u1ed5ng h\u1ee3p c\u00f3 \u0111i\u1ec1u ki\u1ec7n (Conditional Aggregation) \u0111\u1ec3 bi\u1ebfn D\u00f2ng th\u00e0nh C\u1ed9t (Pivot).\n    \n-   V\u1eadn d\u1ee5ng k\u1ef9 thu\u1eadt gh\u00e9p m\u1ea3ng `CROSS JOIN UNNEST` si\u00eau t\u1ed1c \u0111\u1ec3 bi\u1ebfn C\u1ed9t th\u00e0nh D\u00f2ng (Unpivot).\n    \n\n## 1. D\u1ea1ng D\u00e0i (Long) vs D\u1ea1ng R\u1ed9ng (Wide)\n\nTr\u01b0\u1edbc khi xoay tr\u1ee5c, b\u1ea1n c\u1ea7n hi\u1ec3u m\u1ee5c \u0111\u00edch c\u1ee7a hai \u0111\u1ecbnh d\u1ea1ng d\u1eef li\u1ec7u n\u00e0y:\n\n-   **Long Format (D\u1ea1ng d\u00e0i):** L\u00e0 \u0111\u1ecbnh d\u1ea1ng chu\u1ea9n m\u1ef1c c\u1ee7a C\u01a1 s\u1edf d\u1eef li\u1ec7u (Normalized). S\u1ed1 l\u01b0\u1ee3ng c\u1ed9t r\u1ea5t \u00edt, s\u1ed1 l\u01b0\u1ee3ng d\u00f2ng r\u1ea5t nhi\u1ec1u. M\u00e1y t\u00ednh r\u1ea5t th\u00edch \u0111\u1ecdc d\u1ea1ng n\u00e0y (\u0111\u1ec3 `GROUP BY`, `JOIN`), nh\u01b0ng con ng\u01b0\u1eddi \u0111\u1ecdc r\u1ea5t kh\u00f3 nh\u00ecn.\n    \n-   **Wide Format (D\u1ea1ng r\u1ed9ng):** L\u00e0 \u0111\u1ecbnh d\u1ea1ng b\u00e1o c\u00e1o (Cross-tab \/ Pivot Table). S\u1ed1 l\u01b0\u1ee3ng d\u00f2ng \u00edt, s\u1ed1 l\u01b0\u1ee3ng c\u1ed9t tr\u1ea3i d\u00e0i sang ngang (V\u00ed d\u1ee5: Doanh thu chia th\u00e0nh 12 c\u1ed9t cho 12 th\u00e1ng). Con ng\u01b0\u1eddi v\u00e0 c\u00e1c s\u1ebfp r\u1ea5t th\u00edch \u0111\u1ecdc d\u1ea1ng n\u00e0y.\n    \n\n**Nhi\u1ec7m v\u1ee5 c\u1ee7a Data Engineer:** Th\u01b0\u1eddng xuy\u00ean ph\u1ea3i chuy\u1ec3n \u0111\u1ed5i d\u1eef li\u1ec7u t\u1eeb Long sang Wide \u0111\u1ec3 ph\u1ee5c v\u1ee5 Dashboard (Pivot), v\u00e0 \u0111\u00f4i khi ph\u1ea3i l\u00e0m ng\u01b0\u1ee3c l\u1ea1i t\u1eeb Wide v\u1ec1 Long \u0111\u1ec3 \u0111\u01b0a d\u1eef li\u1ec7u r\u00e1c v\u00e0o chu\u1ea9n CSDL (Unpivot).\n\n## 2. PIVOT: Bi\u1ebfn D\u00f2ng th\u00e0nh C\u1ed9t (Row to Column)\n\n> **S\u1ef1 th\u1eadt v\u1ec1 Trino:** Kh\u00e1c v\u1edbi SQL Server hay Snowflake, Trino **KH\u00d4NG C\u00d3** t\u1eeb kh\u00f3a `PIVOT`. Trino tu\u00e2n th\u1ee7 ch\u1eb7t ch\u1ebd chu\u1ea9n ANSI SQL, do \u0111\u00f3 \u0111\u1ec3 xoay tr\u1ee5c, b\u1ea1n s\u1ebd d\u00f9ng k\u1ef9 thu\u1eadt **T\u1ed5ng h\u1ee3p c\u00f3 \u0111i\u1ec1u ki\u1ec7n (Conditional Aggregation)** m\u00e0 ch\u00fang ta \u0111\u00e3 nh\u1eafc s\u01a1 qua \u1edf B\u00e0i 16.\n\nK\u1ef9 thu\u1eadt n\u00e0y s\u1eed d\u1ee5ng `SUM` ho\u1eb7c `COUNT` k\u1ebft h\u1ee3p v\u1edbi m\u1ec7nh \u0111\u1ec1 r\u1ebd nh\u00e1nh `CASE WHEN`.\n\n**B\u00e0i to\u00e1n:** B\u1ea1n c\u00f3 b\u1ea3ng `orders` (d\u1ea1ng Long) ch\u1ee9a doanh thu c\u1ee7a c\u00e1c kh\u00e1ch h\u00e0ng v\u1edbi nhi\u1ec1u tr\u1ea1ng th\u00e1i kh\u00e1c nhau (O, F, P). S\u1ebfp mu\u1ed1n xem m\u1ed9t b\u00e1o c\u00e1o t\u1ed5ng quan: M\u1ed7i kh\u00e1ch h\u00e0ng l\u00e0 1 d\u00f2ng, v\u00e0 c\u00f3 3 c\u1ed9t t\u01b0\u01a1ng \u1ee9ng th\u1ec3 hi\u1ec7n doanh thu cho 3 tr\u1ea1ng th\u00e1i.\n\nSQL\n\n```\n-- D\u1eef li\u1ec7u g\u1ed1c (Long Format): custkey | orderstatus | totalprice\n-- M\u1ee5c ti\u00eau (Wide Format):    custkey | open_rev | finished_rev | pending_rev\n\nSELECT \n    custkey,\n    -- N\u1ebfu tr\u1ea1ng th\u00e1i l\u00e0 'O' th\u00ec l\u1ea5y ti\u1ec1n \u0111\u1ec3 c\u1ed9ng, ng\u01b0\u1ee3c l\u1ea1i c\u1ed9ng 0 (B\u1ecf qua)\n    SUM(CASE WHEN orderstatus = 'O' THEN totalprice ELSE 0 END) AS open_rev,\n    SUM(CASE WHEN orderstatus = 'F' THEN totalprice ELSE 0 END) AS finished_rev,\n    SUM(CASE WHEN orderstatus = 'P' THEN totalprice ELSE 0 END) AS pending_rev\nFROM tpch.tiny.orders\nGROUP BY custkey\nORDER BY custkey;\n\n```\n\n**T\u1ea1i sao c\u00e1ch n\u00e0y t\u1ed1i \u01b0u?** Trino Engine ch\u1ec9 c\u1ea7n qu\u00e9t b\u1ea3ng `orders` \u0111\u00fang m\u1ed9t v\u00f2ng duy nh\u1ea5t (Single Pass). Khi \u0111\u1ecdc \u0111\u1ebfn m\u1ed7i d\u00f2ng, n\u00f3 s\u1ebd d\u00f9ng `CASE WHEN` \u0111\u1ec3 quy\u1ebft \u0111\u1ecbnh xem s\u1ed1 ti\u1ec1n n\u00e0y s\u1ebd \u0111\u01b0\u1ee3c \"th\u1ea3\" v\u00e0o c\u00e1i x\u00f4 (bucket) n\u00e0o trong 3 x\u00f4 `open_rev`, `finished_rev`, `pending_rev`. Hi\u1ec7u n\u0103ng cao h\u01a1n r\u1ea5t nhi\u1ec1u so v\u1edbi vi\u1ec7c d\u00f9ng nhi\u1ec1u l\u1ec7nh `JOIN`.\n\n## 3. UNPIVOT: Bi\u1ebfn C\u1ed9t th\u00e0nh D\u00f2ng (Column to Row)\n\nT\u01b0\u01a1ng t\u1ef1, Trino c\u0169ng **KH\u00d4NG C\u00d3** t\u1eeb kh\u00f3a `UNPIVOT`.\n\n**B\u00e0i to\u00e1n:** B\u1ed9 ph\u1eadn Marketing g\u1eedi cho b\u1ea1n m\u1ed9t file Excel d\u1eef li\u1ec7u ng\u00e2n s\u00e1ch theo d\u1ea1ng Wide Format (m\u1ed7i qu\u00fd l\u00e0 m\u1ed9t c\u1ed9t). B\u1ea1n c\u1ea7n \u0111\u01b0a n\u00f3 v\u00e0o CSDL th\u00e0nh d\u1ea1ng Long Format (C\u1ed9t Quarter, C\u1ed9t Ng\u00e2n s\u00e1ch).\n\n| dept_id | q1_budget | q2_budget | q3_budget | q4_budget |\n| :--- | :--- | :--- | :--- | :--- |\n| **MKT-01** | 1000 | 1500 | 1200 | 2000 |\n\n### C\u00e1ch 1: D\u00f9ng UNION ALL (C\u1ed5 \u0111i\u1ec3n, Ch\u1eadm)\n\nC\u00e1ch truy\u1ec1n th\u1ed1ng l\u00e0 vi\u1ebft 4 c\u00e2u `SELECT` cho 4 qu\u00fd r\u1ed3i d\u00e1n ch\u00fang l\u1ea1i v\u1edbi nhau. _Nh\u01b0\u1ee3c \u0111i\u1ec3m:_ Trino ph\u1ea3i \u0111\u1ecdc b\u1ea3ng d\u1eef li\u1ec7u g\u1ed1c t\u1edbi 4 l\u1ea7n, c\u1ef1c k\u1ef3 t\u1ed1n I\/O n\u1ebfu b\u1ea3ng l\u1edbn.\n\n### C\u00e1ch 2: D\u00f9ng CROSS JOIN UNNEST (Tuy\u1ec7t k\u1ef9 Trino - Nhanh nh\u01b0 ch\u1edbp)\n\nNh\u1edb l\u1ea1i B\u00e0i 31, `UNNEST` c\u00f3 kh\u1ea3 n\u0103ng b\u1ebb g\u00e3y m\u1ea3ng th\u00e0nh c\u00e1c d\u00f2ng. \u0110\u1ec9nh cao c\u1ee7a th\u1ee7 thu\u1eadt Unpivot trong Trino l\u00e0 **gom c\u00e1c c\u1ed9t l\u1ea1i th\u00e0nh M\u1ea3ng (ARRAY)**, sau \u0111\u00f3 d\u00f9ng `UNNEST` \u0111\u1ec3 bung n\u00f3 ra. Trino ch\u1ec9 \u0111\u1ecdc b\u1ea3ng g\u1ed1c \u0111\u00fang 1 l\u1ea7n!\n\nSQL\n\n```\nWITH wide_budget AS (\n    -- Gi\u1ea3 l\u1eadp d\u1eef li\u1ec7u Wide Format\n    SELECT 'MKT-01' AS dept_id, 1000 AS q1_budget, 1500 AS q2_budget, 1200 AS q3_budget, 2000 AS q4_budget\n)\nSELECT \n    w.dept_id,\n    u.quarter_name,\n    u.budget_amount\nFROM wide_budget AS w\n-- Tuy\u1ec7t k\u1ef9 Unpivot:\n-- M\u1ea3ng 1: Hard-code t\u00ean c\u00e1c c\u1ed9t th\u00e0nh chu\u1ed7i\n-- M\u1ea3ng 2: Truy\u1ec1n tr\u1ef1c ti\u1ebfp c\u00e1c c\u1ed9t d\u1eef li\u1ec7u v\u00e0o\nCROSS JOIN UNNEST(\n    ARRAY['Q1', 'Q2', 'Q3', 'Q4'],\n    ARRAY[w.q1_budget, w.q2_budget, w.q3_budget, w.q4_budget]\n) AS u(quarter_name, budget_amount);\n\n```\n\n**K\u1ebft qu\u1ea3 tr\u1ea3 v\u1ec1:** D\u1eef li\u1ec7u t\u1ef1 \u0111\u1ed9ng b\u1ebb th\u00e0nh 4 d\u00f2ng cho ph\u00f2ng Marketing.\n\n| dept_id | quarter_name | budget_amount |\n| :--- | :--- | :--- |\n| **MKT-01** | Q1 | 1000 |\n| **MKT-01** | Q2 | 1500 |\n| **MKT-01** | Q3 | 1200 |\n| **MKT-01** | Q4 | 2000 |\n\n## 4. G\u00f3c nh\u00ecn K\u1ef9 s\u01b0: Khi n\u00e0o n\u00ean Pivot?\n\nL\u00e0 m\u1ed9t Data Engineer, b\u1ea1n c\u1ea7n thi\u1ebft l\u1eadp ranh gi\u1edbi r\u00f5 r\u00e0ng v\u1edbi b\u1ed9 ph\u1eadn BI (Business Intelligence - Nh\u1eefng ng\u01b0\u1eddi t\u1ea1o Dashboard) ho\u1eb7c Data Analyst:\n\n1.  **Tr\u00e1ch nhi\u1ec7m c\u1ee7a Engine (Trino):** Vi\u1ec7c bi\u1ebfn C\u1ed9t th\u00e0nh D\u00f2ng (Unpivot) \u0111\u1ec3 chu\u1ea9n h\u00f3a d\u1eef li\u1ec7u, l\u00e0m s\u1ea1ch, v\u00e0 n\u1ed1i b\u1ea3ng (JOIN) l\u00e0 tr\u00e1ch nhi\u1ec7m c\u1ee7a Data Engineer vi\u1ebft tr\u00ean Trino. Trino l\u00e0m vi\u1ec7c v\u1edbi Long Format r\u1ea5t nhanh.\n    \n2.  **Tr\u00e1ch nhi\u1ec7m c\u1ee7a BI Tool (Tableau, PowerBI, Superset):** Vi\u1ec7c bi\u1ebfn D\u00f2ng th\u00e0nh C\u1ed9t (Pivot) \u0111\u1ec3 hi\u1ec3n th\u1ecb b\u00e1o c\u00e1o **n\u00ean \u0111\u01b0\u1ee3c nh\u01b0\u1eddng l\u1ea1i cho c\u00e1c c\u00f4ng c\u1ee5 BI**. Tr\u1eeb khi h\u1ec7 th\u1ed1ng BI c\u1ee7a b\u1ea1n qu\u00e1 y\u1ebfu, b\u1ea1n m\u1edbi ph\u1ea3i d\u00f9ng SQL `CASE WHEN` \u0111\u1ec3 Pivot s\u1eb5n data d\u01b0\u1edbi t\u1ea7ng Data Warehouse. L\u00fd do l\u00e0 Pivot b\u1eb1ng SQL s\u1ebd l\u00e0m \"c\u1ee9ng h\u00f3a\" (hard-code) c\u00e1c c\u1ed9t, m\u1ed7i khi c\u00f4ng ty c\u00f3 th\u00eam m\u1ed9t ph\u00e2n kh\u00fac m\u1edbi, b\u1ea1n l\u1ea1i ph\u1ea3i s\u1eeda code SQL \u0111\u1ec3 th\u00eam d\u00f2ng `SUM(CASE WHEN...)`. N\u1ebfu \u0111\u1ea9y l\u00ean BI Tool, n\u00f3 s\u1ebd t\u1ef1 \u0111\u1ed9ng nh\u1eadn di\u1ec7n v\u00e0 v\u1ebd ra bi\u1ec3u \u0111\u1ed3 \u0111\u1ed9ng linh ho\u1ea1t h\u01a1n.","published_at":"2026-10-25T09:45:12.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T14:48:03.000000Z","edited_at":"2026-10-11T15:22:17.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":5,"points":0,"views_count":9,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/6fa9f6ed-7faa-4fb9-ae44-572bcaebaf81.png","user":{"data":{"id":184792,"url":"https:\/\/viblo.asia\/u\/nhh","avatar":"81df63c2-e6d9-43a9-85a4-8e807f120997.jpg","name":"Nguy\u1ec5n Huy Ho\u00e0ng","username":"nhh","followers_count":12,"reputation":132,"posts_count":183,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"bien-phap-sql-injection","name":"bi\u1ec7n ph\u00e1p sql injection"}]},"commentators":{"data":[]}},{"id":108858,"title":"Trino SQL B\u00e0i h\u1ecdc 37: Ph\u00e2n t\u00edch c\u00e1c lo\u1ea1i Truy v\u1ea5n l\u1ed3ng (Subqueries) v\u00e0 r\u1ee7i ro hi\u1ec7u n\u0103ng","slug":"vbLbjRplLnk","url":"https:\/\/viblo.asia\/p\/trino-sql-bai-hoc-37-phan-tich-cac-loai-truy-van-long-subqueries-va-rui-ro-hieu-nang-vbLbjRplLnk","user_id":184792,"moderation":null,"transliterated":"trino-sql-bai-hoc-37-phan-tich-cac-loai-truy-van-long-subqueries-va-rui-ro-hieu-nang","contents_short":"M\u1ee5c ti\u00eau b\u00e0i h\u1ecdc:\n\n-   Ph\u00e2n lo\u1ea1i Truy v\u1ea5n l\u1ed3ng d\u1ef1a tr\u00ean s\u1ef1 ph\u1ee5 thu\u1ed9c d\u1eef li\u1ec7u: \u0110\u1ed9c l\u1eadp (Uncorrelated) v\u00e0 T\u01b0\u01a1ng quan (Correlated).\n\n-   Hi\u1ec3u r\u00f5 c\u01a1 ch\u1ebf ho\u1ea1t \u0111\u1ed9ng c\u1ee7a c\u00e1c to\u00e1n t\u1eed \u0111i k\u00e8m Subquery: IN, EXISTS, ANY, ALL.\n\n-   Nh\u1eadn di\u1ec7n \"s\u00e1t th\u1ee7 hi\u1ec7u n\u0103ng\" Correlated Subquery trong m\u00f4i tr\u01b0\u1eddng t\u00ednh to\u00e1n ph\u00e2n t\u00e1n.\n\n-   N\u1eafm v\u1eefng k\u1ef9 thu\u1eadt Decorrelation (Gi\u1ea3i ph\u1ee5 thu\u1ed9c) \u0111\u1ec3 vi\u1ebft l\u1ea1i Subquery th\u00e0nh JOIN t\u1ed1i \u01b0...","contents":"**M\u1ee5c ti\u00eau b\u00e0i h\u1ecdc:**\n\n-   Ph\u00e2n lo\u1ea1i Truy v\u1ea5n l\u1ed3ng d\u1ef1a tr\u00ean s\u1ef1 ph\u1ee5 thu\u1ed9c d\u1eef li\u1ec7u: \u0110\u1ed9c l\u1eadp (Uncorrelated) v\u00e0 T\u01b0\u01a1ng quan (Correlated).\n    \n-   Hi\u1ec3u r\u00f5 c\u01a1 ch\u1ebf ho\u1ea1t \u0111\u1ed9ng c\u1ee7a c\u00e1c to\u00e1n t\u1eed \u0111i k\u00e8m Subquery: `IN`, `EXISTS`, `ANY`, `ALL`.\n    \n-   Nh\u1eadn di\u1ec7n \"s\u00e1t th\u1ee7 hi\u1ec7u n\u0103ng\" Correlated Subquery trong m\u00f4i tr\u01b0\u1eddng t\u00ednh to\u00e1n ph\u00e2n t\u00e1n.\n    \n-   N\u1eafm v\u1eefng k\u1ef9 thu\u1eadt Decorrelation (Gi\u1ea3i ph\u1ee5 thu\u1ed9c) \u0111\u1ec3 vi\u1ebft l\u1ea1i Subquery th\u00e0nh `JOIN` t\u1ed1i \u01b0u.\n    \n\n## 1. Subquery \u0110\u1ed9c l\u1eadp (Uncorrelated Subquery)\n\n\u0110\u00e2y l\u00e0 lo\u1ea1i truy v\u1ea5n con \"l\u00e0nh t\u00ednh\" nh\u1ea5t. N\u00f3 c\u00f3 th\u1ec3 \u0111\u1ee9ng m\u1ed9t m\u00ecnh, ch\u1ea1y th\u1eed \u0111\u1ed9c l\u1eadp m\u00e0 kh\u00f4ng c\u1ea7n quan t\u00e2m \u0111\u1ebfn c\u00e2u truy v\u1ea5n b\u00ean ngo\u00e0i (Outer Query).\n\n**C\u01a1 ch\u1ebf ho\u1ea1t \u0111\u1ed9ng:** Trino s\u1ebd ch\u1ea1y Subquery n\u00e0y **\u0111\u00fang m\u1ed9t l\u1ea7n duy nh\u1ea5t**, l\u01b0u k\u1ebft qu\u1ea3 v\u00e0o b\u1ed9 nh\u1edb, r\u1ed3i l\u1ea5y k\u1ebft qu\u1ea3 \u0111\u00f3 l\u00e0m h\u1eb1ng s\u1ed1 \u0111\u1ec3 ch\u1ea1y c\u00e2u truy v\u1ea5n b\u00ean ngo\u00e0i.\n\n**\u1ee8ng d\u1ee5ng th\u1ef1c t\u1ebf: L\u1ecdc d\u1eef li\u1ec7u b\u1eb1ng m\u1ed9t con s\u1ed1 \u0111\u1ed9ng.** Gi\u1ea3 s\u1eed b\u1ea1n mu\u1ed1n t\u00ecm c\u00e1c \u0111\u01a1n h\u00e0ng c\u00f3 gi\u00e1 tr\u1ecb l\u1edbn h\u01a1n m\u1ee9c trung b\u00ecnh c\u1ee7a to\u00e0n c\u00f4ng ty. B\u1ea1n kh\u00f4ng th\u1ec3 bi\u1ebft m\u1ee9c trung b\u00ecnh l\u00e0 bao nhi\u00eau cho \u0111\u1ebfn khi t\u00ednh n\u00f3 ra.\n\nSQL\n\n```\nSELECT \n    orderkey, \n    totalprice\nFROM tpch.tiny.orders\nWHERE totalprice > (\n    -- Subquery \u0110\u1ed9c l\u1eadp: Ch\u1ea1y 1 l\u1ea7n duy nh\u1ea5t \u0111\u1ec3 ra m\u1ed9t con s\u1ed1 (V\u00ed d\u1ee5: 150000)\n    SELECT AVG(totalprice) FROM tpch.tiny.orders\n);\n\n```\n\n_(Lo\u1ea1i Subquery tr\u1ea3 v\u1ec1 \u0111\u00fang 1 d\u00f2ng, 1 c\u1ed9t nh\u01b0 tr\u00ean \u0111\u01b0\u1ee3c g\u1ecdi l\u00e0 **Scalar Subquery**)._\n\n## 2. L\u00e0m vi\u1ec7c v\u1edbi t\u1eadp h\u1ee3p: IN v\u00e0 EXISTS\n\nN\u1ebfu Subquery tr\u1ea3 v\u1ec1 m\u1ed9t danh s\u00e1ch nhi\u1ec1u d\u00f2ng (thay v\u00ec 1 con s\u1ed1), b\u1ea1n kh\u00f4ng th\u1ec3 d\u00f9ng d\u1ea5u `>` hay `=`. B\u1ea1n ph\u1ea3i d\u00f9ng `IN` ho\u1eb7c `EXISTS`.\n\n-   **D\u00f9ng `IN` (So s\u00e1nh gi\u00e1 tr\u1ecb):** Qu\u00e9t to\u00e0n b\u1ed9 danh s\u00e1ch tr\u1ea3 v\u1ec1 \u0111\u1ec3 xem gi\u00e1 tr\u1ecb c\u00f3 n\u1eb1m trong \u0111\u00f3 kh\u00f4ng. R\u1ea5t t\u1ed1t cho danh s\u00e1ch nh\u1ecf.\n    \n\nSQL\n\n```\n-- T\u00ecm kh\u00e1ch h\u00e0ng thu\u1ed9c c\u00e1c qu\u1ed1c gia \u1edf Ch\u00e2u \u00c1\nSELECT name \nFROM tpch.tiny.customer\nWHERE nationkey IN (\n    SELECT nationkey FROM tpch.tiny.nation WHERE regionkey = 3 -- 3 l\u00e0 ASIA\n);\n\n```\n\n-   **D\u00f9ng `EXISTS` (Ki\u1ec3m tra t\u1ed3n t\u1ea1i):** Kh\u00f4ng quan t\u00e2m gi\u00e1 tr\u1ecb tr\u1ea3 v\u1ec1 l\u00e0 g\u00ec, ch\u1ec9 c\u1ea7n Subquery c\u00f3 tr\u1ea3 v\u1ec1 \u00edt nh\u1ea5t 1 d\u00f2ng l\u00e0 ph\u00e9p th\u1eed tr\u1ea3 v\u1ec1 `TRUE`. Trino t\u1ed1i \u01b0u `EXISTS` r\u1ea5t t\u1ed1t v\u00ec n\u00f3 s\u1eed d\u1ee5ng c\u01a1 ch\u1ebf \"Short-circuit\" (th\u1ea5y 1 d\u00f2ng l\u00e0 d\u1eebng qu\u00e9t ngay).\n    \n\n## 3. Subquery T\u01b0\u01a1ng quan (Correlated Subquery)\n\n\u0110\u00e2y l\u00e0 lo\u1ea1i Subquery nguy hi\u1ec3m nh\u1ea5t. Kh\u00e1c v\u1edbi truy v\u1ea5n \u0111\u1ed9c l\u1eadp, **Subquery T\u01b0\u01a1ng quan b\u1ecb tr\u00f3i bu\u1ed9c v\u1edbi truy v\u1ea5n b\u00ean ngo\u00e0i**. N\u00f3 ch\u1ee9a m\u1ed9t c\u1ed9t thu\u1ed9c v\u1ec1 b\u1ea3ng b\u00ean ngo\u00e0i, do \u0111\u00f3 n\u00f3 kh\u00f4ng th\u1ec3 \u0111\u1ee9ng \u0111\u1ed9c l\u1eadp \u0111\u1ec3 ch\u1ea1y th\u1eed.\n\n**C\u01a1 ch\u1ebf ho\u1ea1t \u0111\u1ed9ng (\u00c1c m\u1ed9ng v\u00f2ng l\u1eb7p):** H\u1ec7 th\u1ed1ng s\u1ebd l\u1ea5y d\u00f2ng th\u1ee9 1 c\u1ee7a b\u1ea3ng ngo\u00e0i, truy\u1ec1n tham s\u1ed1 v\u00e0o Subquery, ch\u1ea1y Subquery 1 l\u1ea7n. L\u1ea5y d\u00f2ng th\u1ee9 2 c\u1ee7a b\u1ea3ng ngo\u00e0i, l\u1ea1i truy\u1ec1n tham s\u1ed1, ch\u1ea1y Subquery l\u1ea7n 2. N\u1ebfu b\u1ea3ng ngo\u00e0i c\u00f3 1 t\u1ef7 d\u00f2ng, **Subquery s\u1ebd b\u1ecb \u00e9p ph\u1ea3i ch\u1ea1y 1 t\u1ef7 l\u1ea7n**.\n\n**V\u00ed d\u1ee5 v\u1ec1 Correlated Subquery \u0111\u1eb7t \u1edf m\u1ec7nh \u0111\u1ec1 SELECT:**\n\nSQL\n\n```\nSELECT \n    c.name,\n    (\n        -- Subquery n\u00e0y ph\u1ee5 thu\u1ed9c v\u00e0o c.custkey c\u1ee7a b\u1ea3ng b\u00ean ngo\u00e0i\n        SELECT SUM(o.totalprice) \n        FROM tpch.tiny.orders AS o \n        WHERE o.custkey = c.custkey\n    ) AS lifetime_value\nFROM tpch.tiny.customer AS c;\n\n```\n\n## 4. G\u00f3c nh\u00ecn K\u1ef9 s\u01b0: R\u1ee7i ro tr\u00ean h\u1ec7 th\u1ed1ng Ph\u00e2n t\u00e1n (Trino)\n\nTrong c\u00e1c c\u01a1 s\u1edf d\u1eef li\u1ec7u truy\u1ec1n th\u1ed1ng (OLTP) nh\u01b0 MySQL hay SQL Server, v\u1edbi v\u00e0i v\u1ea1n d\u00f2ng d\u1eef li\u1ec7u v\u00e0 Index \u0111\u00e1nh \u0111\u1ea7y \u0111\u1ee7, Correlated Subquery v\u1eabn ch\u1ea1y m\u01b0\u1ee3t m\u00e0.\n\nNh\u01b0ng Trino l\u00e0 h\u1ec7 th\u1ed1ng OLAP ph\u00e2n t\u00e1n (Distributed Engine). Tri\u1ebft l\u00fd c\u1ee7a Trino l\u00e0 chia nh\u1ecf kh\u1ed1i d\u1eef li\u1ec7u kh\u1ed5ng l\u1ed3 ra cho nhi\u1ec1u Worker x\u1eed l\u00fd song song (Batch Processing). Correlated Subquery \u00e9p h\u1ec7 th\u1ed1ng ph\u1ea3i th\u1ef1c hi\u1ec7n h\u00e0nh vi **Row-by-Row** (X\u1eed l\u00fd t\u1eebng d\u00f2ng m\u1ed9t - Nested Loop). \u0110i\u1ec1u n\u00e0y ph\u00e1 v\u1ee1 ho\u00e0n to\u00e0n ki\u1ebfn tr\u00fac x\u1eed l\u00fd song song c\u1ee7a Trino, g\u00e2y ra th\u1eaft c\u1ed5 chai CPU (CPU Bottleneck) tr\u1ea7m tr\u1ecdng, th\u1eadm ch\u00ed b\u00e1o l\u1ed7i `Query Exceeded Maximum Time Limit`.\n\nD\u00f9 Trino Optimizer d\u01b0\u1edbi n\u1ec1n c\u00f3 c\u00e1c thu\u1eadt to\u00e1n \"Decorrelation\" (t\u1ef1 \u0111\u1ed9ng bi\u1ebfn Subquery th\u00e0nh Join), nh\u01b0ng v\u1edbi c\u00e1c logic ph\u1ee9c t\u1ea1p, Optimizer s\u1ebd ch\u1ecbu thua v\u00e0 tr\u1ea3 v\u1ec1 l\u1ed7i.\n\n## 5. K\u1ef9 thu\u1eadt Decorrelation (Gi\u1ea3i ph\u1ee5 thu\u1ed9c)\n\n**Quy t\u1eafc v\u00e0ng c\u1ee7a Data Engineer:** H\u00e3y t\u00ecm m\u1ecdi c\u00e1ch vi\u1ebft l\u1ea1i Correlated Subquery th\u00e0nh m\u1ec7nh \u0111\u1ec1 `JOIN` k\u1ebft h\u1ee3p `GROUP BY`.\n\nCh\u00fang ta s\u1ebd c\u1ea5u tr\u00fac l\u1ea1i v\u00ed d\u1ee5 \u1edf ph\u1ea7n 3 \u0111\u1ec3 n\u00f3 ch\u1ea1y c\u1ef1c nhanh tr\u00ean Trino:\n\nSQL\n\n```\n-- C\u00c1CH VI\u1ebeT T\u1ed0I \u01afU (D\u00d9NG LEFT JOIN V\u00c0 GROUP BY)\nSELECT \n    c.name,\n    SUM(o.totalprice) AS lifetime_value\nFROM tpch.tiny.customer AS c\nLEFT JOIN tpch.tiny.orders AS o \n    ON c.custkey = o.custkey\nGROUP BY \n    c.custkey, -- Lu\u00f4n Group By Kh\u00f3a ch\u00ednh \u0111\u1ec3 \u0111\u1ea3m b\u1ea3o an to\u00e0n\n    c.name;\n\n```\n\n_T\u1ea1i sao c\u00e1ch n\u00e0y nhanh?_ Trino s\u1ebd d\u00f9ng Hash Join \u0111\u1ec3 n\u1ed1i 2 b\u1ea3ng trong RAM m\u1ed9t c\u00e1ch song song tr\u00ean to\u00e0n b\u1ed9 Cluster (x\u1eed l\u00fd h\u00e0ng tri\u1ec7u d\u00f2ng c\u00f9ng l\u00fac), thay v\u00ec ph\u1ea3i l\u1eb7p \u0111i l\u1eb7p l\u1ea1i h\u00e0m `SUM` cho t\u1eebng kh\u00e1ch h\u00e0ng nh\u1ecf l\u1ebb.","published_at":"2026-10-25T09:45:05.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T16:53:03.000000Z","edited_at":"2026-10-11T15:21:00.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":4,"points":0,"views_count":9,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/62562774-2aca-45e4-9f8b-069f2724ae7e.png","user":{"data":{"id":184792,"url":"https:\/\/viblo.asia\/u\/nhh","avatar":"81df63c2-e6d9-43a9-85a4-8e807f120997.jpg","name":"Nguy\u1ec5n Huy Ho\u00e0ng","username":"nhh","followers_count":12,"reputation":132,"posts_count":183,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"cac-cau-lenh-trong-ms-sql-server","name":"C\u00e1c C\u00e2u L\u1ec7nh Trong MS SQL Server"}]},"commentators":{"data":[]}},{"id":108857,"title":"Trino SQL B\u00e0i h\u1ecdc 36: T\u1ed1i \u01b0u h\u00f3a truy v\u1ea5n ph\u1ee9c t\u1ea1p v\u1edbi CTE (m\u1ec7nh \u0111\u1ec1 WITH)","slug":"18J2eOYe4YK","url":"https:\/\/viblo.asia\/p\/trino-sql-bai-hoc-36-toi-uu-hoa-truy-van-phuc-tap-voi-cte-menh-de-with-18J2eOYe4YK","user_id":184792,"moderation":null,"transliterated":"trino-sql-bai-hoc-36-toi-uu-hoa-truy-van-phuc-tap-voi-cte-menh-de-with","contents_short":"M\u1ee5c ti\u00eau b\u00e0i h\u1ecdc:\n\n-   Nh\u1eadn di\u1ec7n \"n\u1ed7i \u0111au\" c\u1ee7a Truy v\u1ea5n l\u1ed3ng (Subquery Hell) khi\u1ebfn m\u00e3 ngu\u1ed3n tr\u1edf th\u00e0nh \"Spaghetti Code\".\n\n-   N\u1eafm v\u1eefng c\u00fa ph\u00e1p c\u1ee7a CTE (Common Table Expression) th\u00f4ng qua m\u1ec7nh \u0111\u1ec1 WITH.\n\n-   Thay \u0111\u1ed5i t\u01b0 duy vi\u1ebft SQL t\u1eeb \"Trong ra ngo\u00e0i\" (Inside-out) sang \"T\u1eeb tr\u00ean xu\u1ed1ng d\u01b0\u1edbi\" (Top-down) thu\u1eadn v\u1edbi lu\u1ed3ng t\u01b0 duy con ng\u01b0\u1eddi.\n\n-   G\u00f3c nh\u00ecn K\u1ef9 s\u01b0: Hi\u1ec3u r\u00f5 c\u01a1 ch\u1ebf \"Inlining\" (Ch\u00e8n m\u00e3 n\u1ed9i tuy...","contents":"**M\u1ee5c ti\u00eau b\u00e0i h\u1ecdc:**\n\n-   Nh\u1eadn di\u1ec7n \"n\u1ed7i \u0111au\" c\u1ee7a Truy v\u1ea5n l\u1ed3ng (Subquery Hell) khi\u1ebfn m\u00e3 ngu\u1ed3n tr\u1edf th\u00e0nh \"Spaghetti Code\".\n    \n-   N\u1eafm v\u1eefng c\u00fa ph\u00e1p c\u1ee7a `CTE` (Common Table Expression) th\u00f4ng qua m\u1ec7nh \u0111\u1ec1 `WITH`.\n    \n-   Thay \u0111\u1ed5i t\u01b0 duy vi\u1ebft SQL t\u1eeb \"Trong ra ngo\u00e0i\" (Inside-out) sang \"T\u1eeb tr\u00ean xu\u1ed1ng d\u01b0\u1edbi\" (Top-down) thu\u1eadn v\u1edbi lu\u1ed3ng t\u01b0 duy con ng\u01b0\u1eddi.\n    \n-   **G\u00f3c nh\u00ecn K\u1ef9 s\u01b0:** Hi\u1ec3u r\u00f5 c\u01a1 ch\u1ebf \"Inlining\" (Ch\u00e8n m\u00e3 n\u1ed9i tuy\u1ebfn) c\u1ee7a Trino \u0111\u1ec3 kh\u00f4ng ng\u1ed9 nh\u1eadn v\u1ec1 hi\u1ec7u n\u0103ng c\u1ee7a CTE.\n    \n\n## 1. N\u1ed7i \u0111au mang t\u00ean \"Truy v\u1ea5n l\u1ed3ng\" (Subquery Hell)\n\nTrong ph\u00e2n t\u00edch d\u1eef li\u1ec7u, b\u1ea1n hi\u1ebfm khi ch\u1ec9 d\u00f9ng m\u1ed9t l\u1ec7nh `SELECT` l\u00e0 ra ngay k\u1ebft qu\u1ea3. Th\u01b0\u1eddng th\u00ec b\u1ea1n ph\u1ea3i l\u1ecdc m\u1ed9t b\u1ea3ng, gom nh\u00f3m n\u00f3, r\u1ed3i l\u1ea1i l\u1ea5y k\u1ebft qu\u1ea3 \u0111\u00f3 \u0111i `JOIN` v\u1edbi m\u1ed9t b\u1ea3ng kh\u00e1c \u0111\u00e3 \u0111\u01b0\u1ee3c l\u1ecdc.\n\nC\u00e1ch truy\u1ec1n th\u1ed1ng l\u00e0 vi\u1ebft **Truy v\u1ea5n l\u1ed3ng (Subquery)**: \u0110\u1eb7t m\u1ed9t c\u00e2u `SELECT` b\u00ean trong m\u1ec7nh \u0111\u1ec1 `FROM` c\u1ee7a m\u1ed9t c\u00e2u `SELECT` kh\u00e1c.\n\n**V\u00ed d\u1ee5 \"\u00c1c m\u1ed9ng\":**\n\nSQL\n\n```\n-- \u0110\u1ecdc c\u00e2u SQL n\u00e0y, b\u1ea1n ph\u1ea3i d\u00f2 t\u1eeb l\u00f5i trong c\u00f9ng ra ngo\u00e0i, r\u1ea5t kh\u00f3 b\u1ea3o tr\u00ec\nSELECT \n    c.mktsegment, \n    SUM(o.total_revenue)\nFROM (\n    SELECT custkey, SUM(totalprice) AS total_revenue\n    FROM tpch.tiny.orders\n    WHERE orderdate >= DATE '1995-01-01'\n    GROUP BY custkey\n) AS o\nJOIN (\n    SELECT custkey, mktsegment\n    FROM tpch.tiny.customer\n    WHERE acctbal > 0\n) AS c ON o.custkey = c.custkey\nGROUP BY c.mktsegment;\n\n```\n\nKhi c\u00e1c l\u1edbp l\u1ed3ng nhau \u0111\u1ea1t \u0111\u1ebfn c\u1ea5p \u0111\u1ed9 3 ho\u1eb7c 4, vi\u1ec7c \u0111\u1ecdc hi\u1ec3u v\u00e0 g\u1ee1 l\u1ed7i (debug) m\u1ed9t c\u00e2u SQL tr\u1edf th\u00e0nh c\u1ef1c h\u00ecnh.\n\n## 2. Gi\u1ea3i ph\u00e1p: Kh\u00e1i ni\u1ec7m CTE v\u00e0 m\u1ec7nh \u0111\u1ec1 WITH\n\n**CTE (Common Table Expression - Bi\u1ec3u th\u1ee9c b\u1ea3ng chung)** sinh ra \u0111\u1ec3 gi\u1ea3i c\u1ee9u b\u1ea1n. N\u00f3 cho ph\u00e9p b\u1ea1n \u0111\u1ecbnh ngh\u0129a c\u00e1c c\u00e2u truy v\u1ea5n con th\u00e0nh c\u00e1c **B\u1ea3ng \u1ea3o t\u1ea1m th\u1eddi**, \u0111\u1eb7t cho ch\u00fang m\u1ed9t c\u00e1i t\u00ean d\u1ec5 nh\u1edb, v\u00e0 ghim ch\u00fang l\u00ean tr\u00ean c\u00f9ng c\u1ee7a t\u1eadp l\u1ec7nh.\n\nC\u00fa ph\u00e1p: D\u00f9ng t\u1eeb kh\u00f3a `WITH`, c\u00e1c CTE \u0111\u01b0\u1ee3c c\u00e1ch nhau b\u1edfi d\u1ea5u ph\u1ea9y.\n\nSQL\n\n```\n-- Chuy\u1ec3n \u0111\u1ed5i v\u00ed d\u1ee5 tr\u00ean sang c\u1ea5u tr\u00fac CTE\nWITH recent_orders AS (\n    -- B\u01b0\u1edbc 1: T\u00ednh t\u1ed5ng doanh thu t\u1eebng kh\u00e1ch h\u00e0ng t\u1eeb 1995\n    SELECT custkey, SUM(totalprice) AS total_revenue\n    FROM tpch.tiny.orders\n    WHERE orderdate >= DATE '1995-01-01'\n    GROUP BY custkey\n),\ngood_customers AS (\n    -- B\u01b0\u1edbc 2: L\u1ea5y danh s\u00e1ch kh\u00e1ch h\u00e0ng kh\u00f4ng n\u1ee3 x\u1ea5u\n    SELECT custkey, mktsegment\n    FROM tpch.tiny.customer\n    WHERE acctbal > 0\n)\n-- B\u01b0\u1edbc 3: R\u00e1p c\u00e1c m\u1ea3nh gh\u00e9p l\u1ea1i \u1edf Truy v\u1ea5n ch\u00ednh (Main Query)\nSELECT \n    c.mktsegment, \n    SUM(o.total_revenue)\nFROM recent_orders AS o\nJOIN good_customers AS c ON o.custkey = c.custkey\nGROUP BY c.mktsegment;\n\n```\n\n**L\u1ee3i \u00edch r\u00f5 r\u1ec7t:** M\u00e3 ngu\u1ed3n b\u00e2y gi\u1edd ch\u1ea3y t\u1eeb tr\u00ean xu\u1ed1ng d\u01b0\u1edbi (Top-down) h\u1ec7t nh\u01b0 m\u1ed9t c\u00e2u chuy\u1ec7n. K\u1ef9 s\u01b0 ti\u1ebfp nh\u1eadn code c\u1ee7a b\u1ea1n c\u00f3 th\u1ec3 ch\u1ea1y th\u1eed t\u1eebng kh\u1ed1i CTE \u0111\u1ed9c l\u1eadp \u0111\u1ec3 ki\u1ec3m tra d\u1eef li\u1ec7u tr\u01b0\u1edbc khi ch\u1ea1y to\u00e0n b\u1ed9.\n\n## 3. Kh\u1ea3 n\u0103ng t\u00e1i s\u1eed d\u1ee5ng (Reusability)\n\nM\u1ed9t si\u00eau n\u0103ng l\u1ef1c kh\u00e1c c\u1ee7a CTE l\u00e0 kh\u1ea3 n\u0103ng **t\u00e1i s\u1eed d\u1ee5ng**. N\u1ebfu b\u1ea1n \u0111\u1ecbnh ngh\u0129a m\u1ed9t Subquery \u1edf m\u1ec7nh \u0111\u1ec1 `FROM`, b\u1ea1n ch\u1ec9 d\u00f9ng \u0111\u01b0\u1ee3c n\u00f3 \u0111\u00fang 1 l\u1ea7n. N\u1ebfu mu\u1ed1n d\u00f9ng l\u1ea1i, b\u1ea1n ph\u1ea3i copy\/paste c\u1ea3 \u0111o\u1ea1n code \u0111\u00f3.\n\nV\u1edbi CTE, b\u1ea1n khai b\u00e1o 1 l\u1ea7n \u1edf \u0111\u1ea7u, v\u00e0 c\u00f3 th\u1ec3 g\u1ecdi n\u00f3 nhi\u1ec1u l\u1ea7n trong truy v\u1ea5n ch\u00ednh (v\u00ed d\u1ee5 khi k\u1ebft h\u1ee3p v\u1edbi `UNION ALL` ho\u1eb7c `Self Join`).\n\nSQL\n\n```\nWITH top_10_customers AS (\n    SELECT custkey, SUM(totalprice) AS total_spent\n    FROM tpch.tiny.orders\n    GROUP BY custkey\n    ORDER BY total_spent DESC\n    LIMIT 10\n)\n-- T\u00e1i s\u1eed d\u1ee5ng b\u1ea3ng \u1ea3o top_10_customers 2 l\u1ea7n\nSELECT 'Top 1' AS rank, custkey, total_spent \nFROM top_10_customers \nORDER BY total_spent DESC LIMIT 1\n\nUNION ALL\n\nSELECT 'Top 10', custkey, total_spent \nFROM top_10_customers \nORDER BY total_spent ASC LIMIT 1;\n\n```\n\n## 4. G\u00d3C NH\u00ccN K\u1ef8 S\u01af: C\u1ea1m b\u1eaby \"Inlining\" tr\u00ean Trino\n\nNhi\u1ec1u Data Engineer chuy\u1ec3n t\u1eeb PostgreSQL hay SQL Server sang Trino th\u01b0\u1eddng mang theo m\u1ed9t \"Ng\u1ed9 nh\u1eadn nguy hi\u1ec3m\" v\u1ec1 CTE.\n\n**S\u1ef1 ng\u1ed9 nh\u1eadn:** _\"N\u1ebfu t\u00f4i g\u1ecdi b\u1ea3ng \u1ea3o `top_10_customers` 2 l\u1ea7n trong truy v\u1ea5n ch\u00ednh, Trino s\u1ebd t\u00ednh to\u00e1n CTE \u0111\u00f3 1 l\u1ea7n, l\u01b0u v\u00e0o RAM, v\u00e0 t\u00e1i s\u1eed d\u1ee5ng k\u1ebft qu\u1ea3 t\u1eeb RAM cho 2 l\u1ea7n g\u1ecdi. V\u1eady l\u00e0 t\u1ed1i \u01b0u hi\u1ec7u n\u0103ng!\"_\n\n**S\u1ef1 th\u1eadt ph\u0169 ph\u00e0ng trong Trino:** Trong ki\u1ebfn tr\u00fac c\u1ee7a Trino (v\u00e0 Presto), m\u1eb7c \u0111\u1ecbnh CTE \u0111\u01b0\u1ee3c x\u1eed l\u00fd nh\u01b0 m\u1ed9t d\u1ea1ng **Macro thay th\u1ebf v\u0103n b\u1ea3n (Inlining)**. Trino Engine KH\u00d4NG l\u01b0u (materialize) k\u1ebft qu\u1ea3 c\u1ee7a CTE v\u00e0o b\u1ed9 nh\u1edb. N\u1ebfu b\u1ea1n g\u1ecdi CTE \u0111\u00f3 3 l\u1ea7n \u1edf truy v\u1ea5n ch\u00ednh, Trino s\u1ebd \u00e2m th\u1ea7m copy to\u00e0n b\u1ed9 \u0111o\u1ea1n m\u00e3 SQL b\u00ean trong CTE \u0111\u00f3 v\u00e0 d\u00e1n v\u00e0o 3 v\u1ecb tr\u00ed t\u01b0\u01a1ng \u1ee9ng, sau \u0111\u00f3 **b\u1eaft c\u00e1c Worker qu\u00e9t b\u1ea3ng g\u1ed1c v\u00e0 t\u00ednh to\u00e1n l\u1ea1i t\u1eeb \u0111\u1ea7u 3 l\u1ea7n**.\n\n-   **B\u00e0i h\u1ecdc r\u00fat ra 1:** CTE trong Trino ch\u1ee7 y\u1ebfu mang l\u1ea1i l\u1ee3i \u00edch v\u1ec1 **M\u1eb7t logic v\u00e0 kh\u1ea3 n\u0103ng b\u1ea3o tr\u00ec Code (Readability)**, ch\u1ee9 kh\u00f4ng t\u1ef1 \u0111\u1ed9ng t\u1ed1i \u01b0u h\u00f3a t\u00e0i nguy\u00ean t\u00ednh to\u00e1n nh\u01b0 c\u00e1c RDBMS truy\u1ec1n th\u1ed1ng.\n    \n-   **B\u00e0i h\u1ecdc r\u00fat ra 2:** \u0110\u1eebng l\u1ea1m d\u1ee5ng CTE \u0111\u1ec3 b\u1ecdc c\u00e1c b\u1ea3ng kh\u1ed5ng l\u1ed3 (h\u00e0ng t\u1ef7 d\u00f2ng) n\u1ebfu b\u1ea1n \u0111\u1ecbnh g\u1ecdi l\u1ea1i n\u00f3 nhi\u1ec1u l\u1ea7n trong m\u1ed9t truy v\u1ea5n. Trong tr\u01b0\u1eddng h\u1ee3p \u0111\u00f3, h\u00e3y c\u00e2n nh\u1eafc t\u1ea1o m\u1ed9t b\u1ea3ng v\u1eadt l\u00fd t\u1ea1m th\u1eddi (Table) th\u1eadt s\u1ef1.","published_at":"2026-10-25T09:44:59.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T16:53:03.000000Z","edited_at":"2026-10-11T15:20:37.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":4,"points":0,"views_count":10,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/ba290ca4-3cb6-497f-9fe5-b363f82b999d.png","user":{"data":{"id":184792,"url":"https:\/\/viblo.asia\/u\/nhh","avatar":"81df63c2-e6d9-43a9-85a4-8e807f120997.jpg","name":"Nguy\u1ec5n Huy Ho\u00e0ng","username":"nhh","followers_count":12,"reputation":132,"posts_count":183,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"cac-cau-lenh-trong-ms-sql-server","name":"C\u00e1c C\u00e2u L\u1ec7nh Trong MS SQL Server"}]},"commentators":{"data":[]}},{"id":108495,"title":"C\u1ea5u tr\u00fac d\u1eef li\u1ec7u v\u00e0 Gi\u1ea3i thu\u1eadt B\u00e0i 86: Thu\u1eadt to\u00e1n A* Search - \u0110\u1ecbnh tuy\u1ebfn t\u00ecm \u0111\u01b0\u1eddng \u0111i ng\u1eafn nh\u1ea5t s\u1eed d\u1ee5ng Heuristic.","slug":"lZL9XOXbJQK","url":"https:\/\/viblo.asia\/p\/cau-truc-du-lieu-va-giai-thuat-bai-86-thuat-toan-a-search-dinh-tuyen-tim-duong-di-ngan-nhat-su-dung-heuristic-lZL9XOXbJQK","user_id":182653,"moderation":null,"transliterated":"cau-truc-du-lieu-va-giai-thuat-bai-86-thuat-toan-a-search-dinh-tuyen-tim-duong-di-ngan-nhat-su-dung-heuristic","contents_short":"Trong c\u00e1c b\u00e0i to\u00e1n \u0111\u1ecbnh tuy\u1ebfn c\u01a1 b\u1ea3n, thu\u1eadt to\u00e1n Dijkstra lu\u00f4n \u0111\u1ea3m b\u1ea3o t\u00ecm ra \u0111\u01b0\u1eddng \u0111i ng\u1eafn nh\u1ea5t. Tuy nhi\u00ean, Dijkstra c\u00f3 m\u1ed9t \u0111i\u1ec3m y\u1ebfu ch\u00ed m\u1ea1ng: N\u00f3 b\u1ecb \"m\u00f9\". Dijkstra lan t\u1ecfa s\u1ef1 t\u00ecm ki\u1ebfm ra m\u1ecdi h\u01b0\u1edbng theo h\u00ecnh tr\u00f2n gi\u1ed1ng nh\u01b0 vi\u1ec7c n\u00e9m m\u1ed9t h\u00f2n \u0111\u00e1 xu\u1ed1ng h\u1ed3 n\u01b0\u1edbc. N\u1ebfu b\u1ea1n mu\u1ed1n t\u00ecm \u0111\u01b0\u1eddng t\u1eeb ga B\u1ebfn Th\u00e0nh \u0111\u1ebfn ga Su\u1ed1i Ti\u00ean, Dijkstra s\u1ebd kh\u00e1m ph\u00e1 c\u1ea3 nh\u1eefng con \u0111\u01b0\u1eddng ng\u01b0\u1ee3c h\u01b0\u1edbng \u0111i v\u1ec1 mi\u1ec1n T\u00e2y tr\u01b0\u1edbc khi nh\u1eadn ...","contents":"Trong c\u00e1c b\u00e0i to\u00e1n \u0111\u1ecbnh tuy\u1ebfn c\u01a1 b\u1ea3n, thu\u1eadt to\u00e1n Dijkstra lu\u00f4n \u0111\u1ea3m b\u1ea3o t\u00ecm ra \u0111\u01b0\u1eddng \u0111i ng\u1eafn nh\u1ea5t. Tuy nhi\u00ean, Dijkstra c\u00f3 m\u1ed9t \u0111i\u1ec3m y\u1ebfu ch\u00ed m\u1ea1ng: **N\u00f3 b\u1ecb \"m\u00f9\"**. Dijkstra lan t\u1ecfa s\u1ef1 t\u00ecm ki\u1ebfm ra m\u1ecdi h\u01b0\u1edbng theo h\u00ecnh tr\u00f2n gi\u1ed1ng nh\u01b0 vi\u1ec7c n\u00e9m m\u1ed9t h\u00f2n \u0111\u00e1 xu\u1ed1ng h\u1ed3 n\u01b0\u1edbc. N\u1ebfu b\u1ea1n mu\u1ed1n t\u00ecm \u0111\u01b0\u1eddng t\u1eeb ga B\u1ebfn Th\u00e0nh \u0111\u1ebfn ga Su\u1ed1i Ti\u00ean, Dijkstra s\u1ebd kh\u00e1m ph\u00e1 c\u1ea3 nh\u1eefng con \u0111\u01b0\u1eddng ng\u01b0\u1ee3c h\u01b0\u1edbng \u0111i v\u1ec1 mi\u1ec1n T\u00e2y tr\u01b0\u1edbc khi nh\u1eadn ra m\u1ee5c ti\u00eau th\u1ef1c s\u1ef1 n\u1eb1m \u1edf ph\u00eda \u0110\u00f4ng.\n\nKhi t\u1ed1i \u01b0u h\u00f3a l\u1ed9 tr\u00ecnh giao h\u00e0ng cho shipper ho\u1eb7c l\u1eadp tr\u00ecnh AI cho NPC trong game, s\u1ef1 l\u00e3ng ph\u00ed t\u00ednh to\u00e1n n\u00e0y l\u00e0 kh\u00f4ng th\u1ec3 ch\u1ea5p nh\u1eadn. \u0110\u1ec3 c\u1ea5p cho thu\u1eadt to\u00e1n m\u1ed9t \"\u0111\u00f4i m\u1eaft\" c\u00f3 kh\u1ea3 n\u0103ng nh\u00ecn v\u1ec1 ph\u00eda \u0111\u00edch, n\u0103m 1968, c\u00e1c nh\u00e0 khoa h\u1ecdc t\u1ea1i Stanford \u0111\u00e3 t\u1ea1o ra __A_ (A-Star)_*. \u0110\u00e2y l\u00e0 thu\u1eadt to\u00e1n \u0111\u1ecbnh tuy\u1ebfn ph\u1ed5 bi\u1ebfn nh\u1ea5t th\u1ebf gi\u1edbi hi\u1ec7n nay, tr\u00e1i tim c\u1ee7a Google Maps v\u00e0 m\u1ecdi h\u1ec7 th\u1ed1ng b\u1ea3n \u0111\u1ed3 s\u1ed1.\n\n## 1. C\u00f4ng th\u1ee9c Ma thu\u1eadt: Tr\u00ed tu\u1ec7 nh\u00e2n t\u1ea1o Heuristic\n\nA* v\u1eabn s\u1eed d\u1ee5ng H\u00e0ng \u0111\u1ee3i \u01b0u ti\u00ean (Priority Queue) gi\u1ed1ng nh\u01b0 Dijkstra \u0111\u1ec3 quy\u1ebft \u0111\u1ecbnh xem n\u00ean b\u01b0\u1edbc \u0111i v\u00e0o \u0111\u1ec9nh n\u00e0o ti\u1ebfp theo. Tuy nhi\u00ean, thay v\u00ec ch\u1ec9 d\u1ef1a v\u00e0o kho\u1ea3ng c\u00e1ch \u0111\u00e3 \u0111i, A* \u0111\u00e1nh gi\u00e1 m\u1ed9t \u0111\u1ec9nh $n$ b\u1eb1ng h\u00e0m t\u1ed5ng qu\u00e1t:\n\n$$f(n) = g(n) + h(n)$$\n\nTrong \u0111\u00f3:\n\n-   **$g(n)$ (Chi ph\u00ed th\u1ef1c t\u1ebf):** Kho\u1ea3ng c\u00e1ch ch\u00ednh x\u00e1c t\u1eeb \u0110i\u1ec3m xu\u1ea5t ph\u00e1t (Start) \u0111\u1ebfn \u0111\u1ec9nh $n$ hi\u1ec7n t\u1ea1i. (Ph\u1ea7n n\u00e0y gi\u1ed1ng h\u1ec7t Dijkstra).\n    \n-   **$h(n)$ (H\u00e0m Heuristic - Tr\u1ef1c gi\u00e1c):** \u01af\u1edbc l\u01b0\u1ee3ng kho\u1ea3ng c\u00e1ch t\u1eeb \u0111\u1ec9nh $n$ \u0111\u1ebfn \u0110i\u1ec3m \u0111\u00edch (Goal). \u0110\u00e2y ch\u00ednh l\u00e0 \"\u0111\u00f4i m\u1eaft\" c\u1ee7a A*.\n    \n-   **$f(n)$ (T\u1ed5ng chi ph\u00ed \u01b0\u1edbc t\u00ednh):** Thu\u1eadt to\u00e1n s\u1ebd lu\u00f4n \u01b0u ti\u00ean l\u1ea5y \u0111\u1ec9nh c\u00f3 $f(n)$ nh\u1ecf nh\u1ea5t trong h\u00e0ng \u0111\u1ee3i ra \u0111\u1ec3 duy\u1ec7t tr\u01b0\u1edbc.\n    \n\nNh\u1edd h\u00e0m $h(n)$, thay v\u00ec lan t\u1ecfa v\u00f2ng tr\u00f2n, A* s\u1ebd b\u1ecb \"l\u1ef1c h\u1ea5p d\u1eabn\" c\u1ee7a \u0110i\u1ec3m \u0111\u00edch k\u00e9o lu\u1ed3ng t\u00ecm ki\u1ebfm k\u00e9o gi\u00e3n ra th\u00e0nh h\u00ecnh elip, h\u01b0\u1edbng th\u1eb3ng v\u1ec1 ph\u00eda m\u1ee5c ti\u00eau, b\u1ecf qua c\u00e1c \u0111\u1ec9nh n\u1eb1m ng\u01b0\u1ee3c h\u01b0\u1edbng.\n\n## 2. L\u1ef1a ch\u1ecdn H\u00e0m Heuristic: Ch\u00eca kh\u00f3a c\u1ee7a s\u1ef1 ch\u00ednh x\u00e1c\n\nThu\u1eadt to\u00e1n A* ch\u1ec9 \u0111\u1ea3m b\u1ea3o t\u00ecm \u0111\u01b0\u1ee3c \u0111\u01b0\u1eddng \u0111i ng\u1eafn nh\u1ea5t tuy\u1ec7t \u0111\u1ed1i n\u1ebfu h\u00e0m $h(n)$ l\u00e0 **Admissible (C\u00f3 th\u1ec3 ch\u1ea5p nh\u1eadn \u0111\u01b0\u1ee3c)** \u2014 ngh\u0129a l\u00e0 $h(n)$ _kh\u00f4ng bao gi\u1edd \u0111\u01b0\u1ee3c ph\u00e9p \u01b0\u1edbc l\u01b0\u1ee3ng cao h\u01a1n chi ph\u00ed th\u1ef1c t\u1ebf_. N\u1ebfu n\u00f3 \u0111\u00e1nh gi\u00e1 qu\u00e1 cao, A* c\u00f3 th\u1ec3 b\u1ecf l\u1ee1 con \u0111\u01b0\u1eddng t\u1ed1t nh\u1ea5t.\n\nT\u00f9y v\u00e0o \u0111\u1ecba h\u00ecnh, ch\u00fang ta c\u00f3 c\u00e1c h\u00e0m Heuristic ti\u00eau chu\u1ea9n:\n\n1.  **Manhattan Distance:** D\u00f9ng cho b\u1ea3n \u0111\u1ed3 d\u1ea1ng L\u01b0\u1edbi (Grid) ch\u1ec9 cho ph\u00e9p \u0111i 4 h\u01b0\u1edbng (L\u00ean, Xu\u1ed1ng, Tr\u00e1i, Ph\u1ea3i) nh\u01b0 \u0111\u01b0\u1eddng ph\u1ed1 quy ho\u1ea1ch b\u00e0n c\u1edd.\n    \n    $$h(n) = \\vert{}x_{node} - x_{goal}\\vert{} + \\vert{}y_{node} - y_{goal}\\vert{}$$\n    \n2.  **Euclidean Distance (\u0110\u01b0\u1eddng chim bay):** D\u00f9ng cho b\u1ea3n \u0111\u1ed3 cho ph\u00e9p di chuy\u1ec3n t\u1ef1 do m\u1ecdi h\u01b0\u1edbng.\n    \n    $$h(n) = \\sqrt{(x_{node} - x_{goal})^2 + (y_{node} - y_{goal})^2}$$\n    \n    ## 4. Tri\u1ec3n khai A* Search b\u1eb1ng Golang\n\nD\u01b0\u1edbi \u0111\u00e2y l\u00e0 c\u00e0i \u0111\u1eb7t c\u1ed1t l\u00f5i c\u1ee7a A* tr\u00ean h\u1ec7 t\u1ecda \u0111\u1ed9 L\u01b0\u1edbi 2D (Grid) 4 h\u01b0\u1edbng. (\u0110\u1ec3 m\u00e3 ngu\u1ed3n trong s\u00e1ng, ph\u1ea7n interface `heap` c\u1ee7a Golang \u0111\u01b0\u1ee3c gi\u1ea3 \u0111\u1ecbnh \u0111\u00e3 t\u00edch h\u1ee3p).\n\nGo\n\n```\npackage main\n\nimport (\n\t\"fmt\"\n\t\"math\"\n)\n\n\/\/ C\u1ea5u tr\u00fac m\u1ed9t \u0111i\u1ec3m tr\u00ean b\u1ea3n \u0111\u1ed3 l\u01b0\u1edbi\ntype Point struct {\n\tX, Y int\n}\n\n\/\/ C\u1ea5u tr\u00fac Node trong H\u00e0ng \u0111\u1ee3i \u01b0u ti\u00ean\ntype AStarNode struct {\n\tP      Point\n\tG      float64      \/\/ Chi ph\u00ed t\u1eeb Start \u0111\u1ebfn Node n\u00e0y\n\tH      float64      \/\/ Chi ph\u00ed \u01b0\u1edbc t\u00ednh t\u1eeb Node n\u00e0y \u0111\u1ebfn Goal\n\tF      float64      \/\/ F = G + H\n\tParent *AStarNode   \/\/ D\u00f9ng \u0111\u1ec3 truy xu\u1ea5t ng\u01b0\u1ee3c l\u1ea1i \u0111\u01b0\u1eddng \u0111i\n}\n\n\/\/ H\u00e0m Heuristic: Kho\u1ea3ng c\u00e1ch Manhattan\nfunc manhattan(p, goal Point) float64 {\n\treturn math.Abs(float64(p.X-goal.X)) + math.Abs(float64(p.Y-goal.Y))\n}\n\n\/\/ M\u1ea3ng 4 h\u01b0\u1edbng di chuy\u1ec3n (L\u00ean, Xu\u1ed1ng, Tr\u00e1i, Ph\u1ea3i)\nvar directions = []Point{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}\n\n\/\/ Thu\u1eadt to\u00e1n A*\nfunc AStar(grid [][]int, start, goal Point) []*AStarNode {\n\t\/\/ (Gi\u1ea3 l\u1eadp) Kh\u1edfi t\u1ea1o Priority Queue (Min-Heap) d\u1ef1a tr\u00ean gi\u00e1 tr\u1ecb F\n\t\/\/ openSet := &PriorityQueue{}\n\t\/\/ closedSet l\u01b0u c\u00e1c \u0111\u1ec9nh \u0111\u00e3 duy\u1ec7t\n\tclosedSet := make(map[Point]bool)\n\n\tstartNode := &AStarNode{P: start, G: 0, H: manhattan(start, goal)}\n\tstartNode.F = startNode.G + startNode.H\n\t\n\t\/\/ openSet.Push(startNode) \/\/ Gi\u1ea3 \u0111\u1ecbnh Push v\u00e0o Heap\n\t\n\t\/\/ Kh\u1edfi t\u1ea1o v\u00f2ng l\u1eb7p m\u00f4 ph\u1ecfng\n\t\/\/ for openSet.Len() > 0 {\n\t\t\/\/ current := openSet.Pop().(*AStarNode) \/\/ L\u1ea5y Node c\u00f3 F nh\u1ecf nh\u1ea5t\n\t\tcurrent := startNode \/\/ (M\u00f4 ph\u1ecfng)\n\n\t\t\/\/ 1. Ki\u1ec3m tra \u0111i\u1ec1u ki\u1ec7n \u0111\u00edch\n\t\tif current.P == goal {\n\t\t\treturn reconstructPath(current)\n\t\t}\n\n\t\tclosedSet[current.P] = true\n\n\t\t\/\/ 2. M\u1edf r\u1ed9ng c\u00e1c \u00f4 l\u00e2n c\u1eadn\n\t\tfor _, dir := range directions {\n\t\t\tneighbor := Point{X: current.P.X + dir.X, Y: current.P.Y + dir.Y}\n\n\t\t\t\/\/ B\u1ecf qua n\u1ebfu ra kh\u1ecfi b\u1ea3n \u0111\u1ed3, l\u00e0 v\u1eadt c\u1ea3n (grid == 1), ho\u1eb7c \u0111\u00e3 duy\u1ec7t qua\n\t\t\tif !isValid(grid, neighbor) || grid[neighbor.Y][neighbor.X] == 1 || closedSet[neighbor] {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t\/\/ Chi ph\u00ed \u0111i 1 b\u01b0\u1edbc b\u1eb1ng 1\n\t\t\ttentativeG := current.G + 1\n\n\t\t\t\/\/ T\u00ednh to\u00e1n Node m\u1edbi\n\t\t\t\/\/ neighborNode := &AStarNode{\n\t\t\t\/\/\t P: neighbor,\n\t\t\t\/\/\t G: tentativeG,\n\t\t\t\/\/\t H: manhattan(neighbor, goal),\n\t\t\t\/\/\t Parent: current,\n\t\t\t\/\/ }\n\t\t\t\/\/ neighborNode.F = neighborNode.G + neighborNode.H\n\t\t\t\n\t\t\t\/\/ C\u1eadp nh\u1eadt l\u1ea1i trong openSet n\u1ebfu t\u00ecm \u0111\u01b0\u1ee3c G t\u1ed1t h\u01a1n (Code th\u1ef1c t\u1ebf c\u1ea7n c\u1eadp nh\u1eadt l\u1ea1i Heap)\n\t\t\t\/\/ openSet.Push(neighborNode)\n\t\t}\n\t\/\/ }\n\treturn nil \/\/ Kh\u00f4ng t\u00ecm th\u1ea5y \u0111\u01b0\u1eddng\n}\n\n\/\/ H\u00e0m truy v\u1ebft \u0111\u01b0\u1eddng \u0111i t\u1eeb \u0110\u00edch ng\u01b0\u1ee3c v\u1ec1 Start\nfunc reconstructPath(node *AStarNode) []*AStarNode {\n\tvar path []*AStarNode\n\tfor node != nil {\n\t\tpath = append([]*AStarNode{node}, path...) \/\/ Ch\u00e8n l\u00ean \u0111\u1ea7u\n\t\tnode = node.Parent\n\t}\n\treturn path\n}\n\nfunc isValid(grid [][]int, p Point) bool {\n\treturn p.Y >= 0 && p.Y < len(grid) && p.X >= 0 && p.X < len(grid[0])\n}\n\nfunc main() {\n\t\/\/ L\u01b0\u1edbi 5x5. 0 l\u00e0 \u0111\u01b0\u1eddng \u0111i, 1 l\u00e0 t\u01b0\u1eddng.\n\tgrid := [][]int{\n\t\t{0, 0, 0, 0, 0},\n\t\t{0, 1, 1, 1, 0},\n\t\t{0, 0, 0, 1, 0},\n\t\t{0, 1, 0, 0, 0},\n\t\t{0, 0, 0, 0, 0},\n\t}\n\tstart := Point{0, 0}\n\tgoal := Point{4, 4}\n\n\tfmt.Printf(\"T\u00ecm \u0111\u01b0\u1eddng t\u1eeb %v \u0111\u1ebfn %v...\\n\", start, goal)\n\t\/\/ G\u1ecdi AStar (\u0111\u00e3 r\u00fat g\u1ecdn m\u00f4 ph\u1ecfng)\n}\n\n```\n\n## 5. Ph\u00e2n t\u00edch Hi\u1ec7u n\u0103ng v\u00e0 \u1ee8ng d\u1ee5ng Th\u1ef1c t\u1ebf\n\n-   **Th\u1eddi gian Truy v\u1ea5n (Time Complexity):** \u1ede tr\u01b0\u1eddng h\u1ee3p x\u1ea5u nh\u1ea5t (b\u1ea3n \u0111\u1ed3 tr\u1ed1ng r\u1ed7ng ho\u1eb7c heuristic t\u1ed3i $h(n)=0$), A* tho\u00e1i h\u00f3a th\u00e0nh thu\u1eadt to\u00e1n Dijkstra, t\u1ed1n $O(E + V \\log V)$. V\u1edbi h\u00e0m heuristic xu\u1ea5t s\u1eafc, th\u1eddi gian ti\u1ec7m c\u1eadn $O(d)$ (v\u1edbi $d$ l\u00e0 \u0111\u1ed9 d\u00e0i \u0111\u01b0\u1eddng \u0111i ng\u1eafn nh\u1ea5t), c\u1ef1c k\u1ef3 ch\u1edbp nho\u00e1ng.\n    \n-   **Kh\u00f4ng gian (Space Complexity):** $O(V)$ v\u00ec thu\u1eadt to\u00e1n ph\u1ea3i l\u01b0u to\u00e0n b\u1ed9 c\u00e1c Node bi\u00ean (Frontier) v\u00e0o trong RAM \u0111\u1ec3 qu\u1ea3n l\u00fd Priority Queue. \u0110\u00e2y l\u00e0 gi\u1edbi h\u1ea1n l\u1edbn nh\u1ea5t c\u1ee7a A* \u0111\u1ed1i v\u1edbi c\u00e1c b\u1ea3n \u0111\u1ed3 kh\u1ed5ng l\u1ed3, d\u1eabn \u0111\u1ebfn s\u1ef1 ra \u0111\u1eddi c\u1ee7a c\u00e1c bi\u1ebfn th\u1ec3 ti\u1ebft ki\u1ec7m RAM nh\u01b0 __IDA_ (Iterative Deepening A_).\n    \n\n**\u1ee8ng d\u1ee5ng c\u1ed1t l\u00f5i:**\n\n1.  **AI Di chuy\u1ec3n trong Game (Pathfinding):** C\u00e1c nh\u00e2n v\u1eadt NPC, l\u00ednh g\u00e1c, ho\u1eb7c qu\u00e1i v\u1eadt t\u00ecm \u0111\u01b0\u1eddng ch\u1ea1y \u0111\u1ebfn nh\u00e2n v\u1eadt ch\u00ednh trong \u0111\u1ecba h\u00ecnh ph\u1ee9c t\u1ea1p c\u00f3 ch\u01b0\u1edbng ng\u1ea1i v\u1eadt.\n    \n2.  **\u0110\u1ecbnh tuy\u1ebfn Logistics:** Khi h\u1ec7 th\u1ed1ng t\u1ef1 \u0111\u1ed9ng h\u00f3a \u0111i\u1ec1u ph\u1ed1i robot n\u00e2ng h\u00e0ng (AGV) trong c\u00e1c kho b\u00e3i kh\u1ed5ng l\u1ed3, A* \u0111\u1ecbnh tuy\u1ebfn m\u01b0\u1ee3t m\u00e0 \u0111\u1ec3 n\u00e9 c\u00e1c gi\u00e1 k\u1ec7 v\u00e0 robot kh\u00e1c.\n    \n3.  **C\u00f4ng ngh\u1ec7 B\u1ea3n \u0111\u1ed3 (Maps & Navigation):** C\u00e1c h\u1ec7 th\u1ed1ng ch\u1ec9 \u0111\u01b0\u1eddng th\u1eddi gian th\u1ef1c k\u1ebft h\u1ee3p A* v\u1edbi \u0111\u1ed3 th\u1ecb m\u1ea1ng l\u01b0\u1edbi \u0111\u01b0\u1eddng giao th\u00f4ng \u0111\u1ec3 li\u00ean t\u1ee5c t\u00ednh to\u00e1n l\u1ea1i qu\u1ef9 \u0111\u1ea1o.\n    \n\nKhi b\u00e0i to\u00e1n \u0111\u1ecbnh tuy\u1ebfn \u0111i qua m\u1ed9t \u0111i\u1ec3m \u0111\u00edch \u0111\u00e3 ho\u00e0n th\u00e0nh, th\u00e1ch th\u1ee9c v\u0129 m\u00f4 ti\u1ebfp theo c\u1ee7a c\u00e1c k\u1ef9 s\u01b0 m\u1ea1ng l\u00e0 l\u00e0m sao \u0111\u1ec3 b\u01a1m m\u1ed9t \"d\u00f2ng ch\u1ea3y\" d\u1eef li\u1ec7u ho\u1eb7c h\u00e0ng h\u00f3a qua m\u1ed9t m\u1ea1ng l\u01b0\u1edbi \u1ed1ng d\u1eabn c\u00f3 s\u1ee9c ch\u1ee9a (Capacity) gi\u1edbi h\u1ea1n m\u00e0 kh\u00f4ng l\u00e0m t\u1eafc ngh\u1ebdn h\u1ec7 th\u1ed1ng.","published_at":"2026-10-25T09:43:18.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T16:53:03.000000Z","edited_at":"2026-10-08T00:39:24.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":5,"points":0,"views_count":9,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/2f61117b-7df0-47c4-99ae-17b15f4801e9.png","user":{"data":{"id":182653,"url":"https:\/\/viblo.asia\/u\/hhoang","avatar":"8392e404-ea43-497f-8b18-3777e24dc6ab.jpg","name":"Huy Ho\u00e0ng","username":"hhoang","followers_count":202,"reputation":14064,"posts_count":1576,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"cau-truc-du-lieu","name":"c\u1ea5u tr\u00fac d\u1eef li\u1ec7u"}]},"commentators":{"data":[]}},{"id":108494,"title":"C\u1ea5u tr\u00fac d\u1eef li\u1ec7u v\u00e0 Gi\u1ea3i thu\u1eadt B\u00e0i 85: Disjoint Set Union (DSU) - Qu\u1ea3n l\u00fd t\u1eadp h\u1ee3p r\u1eddi r\u1ea1c v\u00e0 thu\u1eadt to\u00e1n Kruskal.","slug":"oKLnqjqNJQO","url":"https:\/\/viblo.asia\/p\/cau-truc-du-lieu-va-giai-thuat-bai-85-disjoint-set-union-dsu-quan-ly-tap-hop-roi-rac-va-thuat-toan-kruskal-oKLnqjqNJQO","user_id":182653,"moderation":null,"transliterated":"cau-truc-du-lieu-va-giai-thuat-bai-85-disjoint-set-union-dsu-quan-ly-tap-hop-roi-rac-va-thuat-toan-kruskal","contents_short":"Trong B\u00e0i 74 v\u00e0 75, b\u1ea1n \u0111\u00e3 gi\u1ea3i quy\u1ebft c\u00e1c b\u00e0i to\u00e1n tr\u00ean m\u1ed9t \u0111\u1ed3 th\u1ecb d\u1ea1ng C\u00e2y (Tree) t\u0129nh b\u1eb1ng HLD v\u00e0 Binary Lifting. Tuy nhi\u00ean, trong th\u1ef1c t\u1ebf k\u1ef9 thu\u1eadt t\u1ea1i Hasaki ho\u1eb7c h\u1ec7 th\u1ed1ng v\u00e9 t\u1ef1 \u0111\u1ed9ng (AFC) c\u1ee7a tuy\u1ebfn Metro, b\u1ea1n th\u01b0\u1eddng ph\u1ea3i \u0111\u1ed1i m\u1eb7t v\u1edbi \u0111\u1ed3 th\u1ecb \u0111\u1ed9ng \u2014 n\u01a1i c\u00e1c k\u1ebft n\u1ed1i gi\u1eefa c\u00e1c tr\u1ea1m ho\u1eb7c m\u1ea1ng l\u01b0\u1edbi m\u00e1y ch\u1ee7 li\u00ean t\u1ee5c \u0111\u01b0\u1ee3c th\u00eam v\u00e0o.\n\nL\u00e0m sao \u0111\u1ec3 bi\u1ebft Tr\u1ea1m A v\u00e0 Tr\u1ea1m B \u0111\u00e3 th\u00f4ng m\u1ea1ng v\u1edbi nhau hay ch\u01b0a? N\u1ebf...","contents":"Trong B\u00e0i 74 v\u00e0 75, b\u1ea1n \u0111\u00e3 gi\u1ea3i quy\u1ebft c\u00e1c b\u00e0i to\u00e1n tr\u00ean m\u1ed9t \u0111\u1ed3 th\u1ecb d\u1ea1ng C\u00e2y (Tree) t\u0129nh b\u1eb1ng HLD v\u00e0 Binary Lifting. Tuy nhi\u00ean, trong th\u1ef1c t\u1ebf k\u1ef9 thu\u1eadt t\u1ea1i Hasaki ho\u1eb7c h\u1ec7 th\u1ed1ng v\u00e9 t\u1ef1 \u0111\u1ed9ng (AFC) c\u1ee7a tuy\u1ebfn Metro, b\u1ea1n th\u01b0\u1eddng ph\u1ea3i \u0111\u1ed1i m\u1eb7t v\u1edbi **\u0111\u1ed3 th\u1ecb \u0111\u1ed9ng** \u2014 n\u01a1i c\u00e1c k\u1ebft n\u1ed1i gi\u1eefa c\u00e1c tr\u1ea1m ho\u1eb7c m\u1ea1ng l\u01b0\u1edbi m\u00e1y ch\u1ee7 li\u00ean t\u1ee5c \u0111\u01b0\u1ee3c th\u00eam v\u00e0o.\n\nL\u00e0m sao \u0111\u1ec3 bi\u1ebft Tr\u1ea1m A v\u00e0 Tr\u1ea1m B \u0111\u00e3 th\u00f4ng m\u1ea1ng v\u1edbi nhau hay ch\u01b0a? N\u1ebfu d\u00f9ng thu\u1eadt to\u00e1n duy\u1ec7t DFS\/BFS m\u1ed7i l\u1ea7n ki\u1ec3m tra, h\u1ec7 th\u1ed1ng s\u1ebd ch\u00ecm trong v\u00f2ng l\u1eb7p $O(N)$ t\u1ed1n k\u00e9m. \u0110\u1ec3 x\u1eed l\u00fd c\u00e1c b\u00e0i to\u00e1n \"k\u1ebft n\u1ed1i m\u1ea1ng l\u01b0\u1edbi\" n\u00e0y trong th\u1eddi gian **x\u1ea5p x\u1ec9 $O(1)$**, gi\u1edbi khoa h\u1ecdc m\u00e1y t\u00ednh s\u1eed d\u1ee5ng **Disjoint Set Union (DSU)** \u2014 hay c\u00f2n g\u1ecdi l\u00e0 C\u1ea5u tr\u00fac d\u1eef li\u1ec7u T\u00ecm-v\u00e0-H\u1ee3p (Union-Find).\n\n## 1. B\u1ea3n ch\u1ea5t c\u1ee7a Disjoint Set Union (DSU)\n\nDSU l\u00e0 m\u1ed9t c\u1ea5u tr\u00fac d\u1eef li\u1ec7u duy tr\u00ec m\u1ed9t t\u1eadp h\u1ee3p c\u00e1c nh\u00f3m (components) r\u1eddi r\u1ea1c. N\u00f3 h\u1ed7 tr\u1ee3 hai thao t\u00e1c c\u1ed1t l\u00f5i:\n\n1.  **Find (T\u00ecm ki\u1ebfm):** X\u00e1c \u0111\u1ecbnh xem m\u1ed9t ph\u1ea7n t\u1eed $X$ \u0111ang thu\u1ed9c nh\u00f3m n\u00e0o. Th\u01b0\u1eddng \u0111\u01b0\u1ee3c d\u00f9ng \u0111\u1ec3 ki\u1ec3m tra xem $X$ v\u00e0 $Y$ c\u00f3 \u0111ang c\u00f9ng chung m\u1ed9t nh\u00f3m hay kh\u00f4ng.\n    \n2.  **Union (H\u1ee3p nh\u1ea5t):** G\u1ed9p nh\u00f3m ch\u1ee9a $X$ v\u00e0 nh\u00f3m ch\u1ee9a $Y$ l\u1ea1i th\u00e0nh m\u1ed9t nh\u00f3m duy nh\u1ea5t.\n    \n\nThay v\u00ec l\u01b0u tr\u1eef ph\u1ee9c t\u1ea1p, DSU bi\u1ec3u di\u1ec5n m\u1ed7i nh\u00f3m nh\u01b0 m\u1ed9t **C\u00e2y (Tree)** l\u1ed9n ng\u01b0\u1ee3c. M\u1ed7i ph\u1ea7n t\u1eed ch\u1ec9 c\u1ea7n nh\u1edb duy nh\u1ea5t m\u1ed9t th\u00f4ng tin: **Ai l\u00e0 cha tr\u1ef1c ti\u1ebfp c\u1ee7a m\u00ecnh?** (`parent[i]`).\n\n-   \u0110\u1ec9nh cao nh\u1ea5t c\u1ee7a c\u00e2y (Root) \u0111\u01b0\u1ee3c g\u1ecdi l\u00e0 **Ng\u01b0\u1eddi \u0111\u1ea1i di\u1ec7n (Representative)** c\u1ee7a c\u1ea3 nh\u00f3m. \u0110\u1ed1i v\u1edbi Root, cha c\u1ee7a n\u00f3 l\u00e0 ch\u00ednh n\u00f3 (`parent[Root] = Root`).\n    \n-   \u0110\u1ec3 bi\u1ebft hai ph\u1ea7n t\u1eed c\u00f3 chung nh\u00f3m hay kh\u00f4ng, ta b\u00f2 l\u00ean t\u00ecm Ng\u01b0\u1eddi \u0111\u1ea1i di\u1ec7n c\u1ee7a c\u1ea3 hai. N\u1ebfu tr\u00f9ng nhau, ch\u00fang \u0111\u00e3 th\u00f4ng m\u1ea1ng.\n    \n\n## 2. Hai ph\u00e9p t\u1ed1i \u01b0u th\u1ea7n th\u00e1nh: G\u1ed9p theo H\u1ea1ng v\u00e0 N\u00e9n \u0111\u01b0\u1eddng \u0111i\n\nN\u1ebfu ch\u00fang ta ch\u1ec9 n\u1ed1i b\u1eeba c\u00e1c \u0111\u1ec9nh l\u1ea1i v\u1edbi nhau, c\u00e2y c\u00f3 th\u1ec3 b\u1ecb tho\u00e1i h\u00f3a th\u00e0nh m\u1ed9t \u0111\u01b0\u1eddng th\u1eb3ng d\u00e0i ngo\u1eb1ng (Linked List), khi\u1ebfn thao t\u00e1c Find t\u1ed1n $O(N)$. \u0110\u1ec3 \u00e9p th\u1eddi gian v\u1ec1 m\u1ee9c ti\u1ec7m c\u1eadn h\u1eb1ng s\u1ed1, DSU s\u1eed d\u1ee5ng 2 k\u1ef9 thu\u1eadt t\u1ed1i \u01b0u:\n\n### A. Union by Rank (G\u1ed9p theo k\u00edch th\u01b0\u1edbc\/chi\u1ec1u cao)\n\nKhi h\u1ee3p nh\u1ea5t hai nh\u00f3m, ta kh\u00f4ng n\u1ed1i ng\u1eabu nhi\u00ean. Ta duy tr\u00ec th\u00eam m\u1ed9t m\u1ea3ng `rank` (ho\u1eb7c `size`) l\u01b0u chi\u1ec1u cao ho\u1eb7c s\u1ed1 l\u01b0\u1ee3ng ph\u1ea7n t\u1eed c\u1ee7a c\u00e1i c\u00e2y.\n\n-   **Quy t\u1eafc:** Lu\u00f4n n\u1ed1i g\u1ed1c c\u1ee7a c\u00e2y **nh\u1ecf h\u01a1n** v\u00e0o l\u00e0m con c\u1ee7a g\u1ed1c c\u00e2y **l\u1edbn h\u01a1n**. \u0110i\u1ec1u n\u00e0y \u0111\u1ea3m b\u1ea3o chi\u1ec1u cao c\u1ee7a c\u00e2y t\u0103ng l\u00ean c\u1ef1c k\u1ef3 ch\u1eadm (t\u1ed1i \u0111a l\u00e0 $O(\\log N)$).\n    \n\n### B. Path Compression (N\u00e9n \u0111\u01b0\u1eddng \u0111i)\n\n\u0110\u00e2y l\u00e0 ph\u00e9p t\u1ed1i \u01b0u b\u00e1 \u0111\u1ea1o nh\u1ea5t c\u1ee7a DSU. Khi th\u1ef1c hi\u1ec7n h\u00e0m `Find(X)` \u0111\u1ec3 t\u00ecm Ng\u01b0\u1eddi \u0111\u1ea1i di\u1ec7n, thu\u1eadt to\u00e1n ph\u1ea3i l\u1ed9i ng\u01b0\u1ee3c d\u00f2ng t\u1eeb $X$ l\u00ean Root.\n\n-   **Quy t\u1eafc:** Thay v\u00ec ch\u1ec9 \u0111i l\u00ean v\u00e0 tr\u1ea3 v\u1ec1 k\u1ebft qu\u1ea3, thu\u1eadt to\u00e1n s\u1ebd \"b\u1ebb\" con tr\u1ecf `parent` c\u1ee7a $X$ (v\u00e0 m\u1ecdi \u0111\u1ec9nh tr\u00ean \u0111\u01b0\u1eddng \u0111i) **tr\u1ecf th\u1eb3ng tr\u1ef1c ti\u1ebfp v\u00e0o Root**.\n    \n-   Nh\u1edd v\u1eady, \u1edf l\u1ea7n Find ti\u1ebfp theo, $X$ s\u1ebd nh\u1ea3y \u0111\u1ebfn Root ch\u1ec9 trong \u0111\u00fang 1 b\u01b0\u1edbc!\n\n![image.png](https:\/\/images.viblo.asia\/9257bbb4-ffab-47d3-b820-3b171977fdad.png)\n\nK\u1ebft h\u1ee3p c\u1ea3 hai k\u1ef9 thu\u1eadt n\u00e0y, \u0111\u1ed9 ph\u1ee9c t\u1ea1p c\u1ee7a DSU gi\u1ea3m xu\u1ed1ng **$O(\\alpha(N))$** \u2014 trong \u0111\u00f3 $\\alpha(N)$ l\u00e0 h\u00e0m ng\u01b0\u1ee3c Ackermann. V\u1edbi $N$ l\u1edbn b\u1eb1ng s\u1ed1 nguy\u00ean t\u1eed trong v\u0169 tr\u1ee5, $\\alpha(N)$ c\u0169ng kh\u00f4ng v\u01b0\u1ee3t qu\u00e1 $4$. Ngh\u0129a l\u00e0 DSU ch\u1ea1y v\u1edbi t\u1ed1c \u0111\u1ed9 **$O(1)$ tuy\u1ec7t \u0111\u1ed1i**.\n\n## 3. Thu\u1eadt to\u00e1n Kruskal: T\u00ecm C\u00e2y Khung Nh\u1ecf Nh\u1ea5t (MST)\n\nM\u1ed9t trong nh\u1eefng \u1ee9ng d\u1ee5ng v\u0129 \u0111\u1ea1i nh\u1ea5t c\u1ee7a DSU l\u00e0 **Thu\u1eadt to\u00e1n Kruskal**.\n\nGi\u1ea3 s\u1eed h\u1ec7 th\u1ed1ng AFC c\u1ee7a Metro Line 1 c\u00f3 14 nh\u00e0 ga. B\u1ea1n c\u1ea7n r\u1ea3i d\u00e2y c\u00e1p quang k\u1ebft n\u1ed1i t\u1ea5t c\u1ea3 c\u00e1c ga n\u00e0y l\u1ea1i v\u1edbi nhau sao cho **t\u1ed5ng chi\u1ec1u d\u00e0i c\u00e1p l\u00e0 ng\u1eafn nh\u1ea5t**, nh\u01b0ng m\u1ecdi ga \u0111\u1ec1u ph\u1ea3i \u0111\u01b0\u1ee3c th\u00f4ng m\u1ea1ng. \u0110\u1ed3 th\u1ecb n\u00e0y \u0111\u01b0\u1ee3c g\u1ecdi l\u00e0 **Minimum Spanning Tree (MST)**.\n\nThu\u1eadt to\u00e1n Kruskal s\u1eed d\u1ee5ng DSU \u0111\u1ec3 gi\u1ea3i b\u00e0i to\u00e1n n\u00e0y m\u1ed9t c\u00e1ch v\u00f4 c\u00f9ng thanh l\u1ecbch:\n\n1.  L\u1ea5y t\u1ea5t c\u1ea3 c\u00e1c c\u1ea1nh (\u0111o\u1ea1n c\u00e1p) c\u1ee7a \u0111\u1ed3 th\u1ecb v\u00e0 **s\u1eafp x\u1ebfp ch\u00fang t\u0103ng d\u1ea7n** theo chi\u1ec1u d\u00e0i (tr\u1ecdng s\u1ed1).\n    \n2.  Kh\u1edfi t\u1ea1o DSU, coi m\u1ed7i nh\u00e0 ga ban \u0111\u1ea7u l\u00e0 m\u1ed9t t\u1eadp h\u1ee3p r\u1eddi r\u1ea1c.\n    \n3.  Duy\u1ec7t qua danh s\u00e1ch c\u1ea1nh \u0111\u00e3 s\u1eafp x\u1ebfp (t\u1eeb ng\u1eafn nh\u1ea5t \u0111\u1ebfn d\u00e0i nh\u1ea5t).\n    \n4.  V\u1edbi m\u1ed7i c\u1ea1nh n\u1ed1i Tr\u1ea1m $U$ v\u00e0 Tr\u1ea1m $V$:\n    \n    -   D\u00f9ng `Find` \u0111\u1ec3 xem $U$ v\u00e0 $V$ \u0111\u00e3 th\u00f4ng m\u1ea1ng ch\u01b0a.\n        \n    -   **N\u1ebfu ch\u01b0a:** N\u1ed1i ch\u00fang l\u1ea1i b\u1eb1ng `Union` v\u00e0 \u0111\u01b0a c\u1ea1nh n\u00e0y v\u00e0o MST.\n        \n    -   **N\u1ebfu \u0111\u00e3 th\u00f4ng r\u1ed3i:** B\u1ecf qua c\u1ea1nh n\u00e0y (v\u00ec n\u1ebfu n\u1ed1i th\u00eam s\u1ebd t\u1ea1o th\u00e0nh **Chu tr\u00ecnh - Cycle**, g\u00e2y l\u00e3ng ph\u00ed c\u00e1p).\n        \n5.  D\u1eebng l\u1ea1i khi \u0111\u00e3 n\u1ed1i \u0111\u1ee7 $N-1$ c\u1ea1nh.\n\n## 5. Tri\u1ec3n khai DSU v\u00e0 Kruskal b\u1eb1ng Golang\n\nD\u01b0\u1edbi \u0111\u00e2y l\u00e0 m\u00e3 ngu\u1ed3n chu\u1ea9n m\u1ef1c Golang t\u00edch h\u1ee3p c\u1ea3 Path Compression, Union by Rank v\u00e0 Thu\u1eadt to\u00e1n Kruskal.\n\nGo\n\n```\npackage main\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n)\n\n\/\/ C\u1ea5u tr\u00fac Disjoint Set Union (DSU)\ntype DSU struct {\n\tparent []int\n\trank   []int\n}\n\nfunc NewDSU(n int) *DSU {\n\tdsu := &DSU{\n\t\tparent: make([]int, n),\n\t\trank:   make([]int, n),\n\t}\n\t\/\/ Ban \u0111\u1ea7u, m\u1ed7i \u0111\u1ec9nh t\u1ef1 l\u00e0m cha c\u1ee7a ch\u00ednh n\u00f3\n\tfor i := 0; i < n; i++ {\n\t\tdsu.parent[i] = i\n\t\tdsu.rank[i] = 0\n\t}\n\treturn dsu\n}\n\n\/\/ H\u00e0m Find t\u00edch h\u1ee3p Path Compression (N\u00e9n \u0111\u01b0\u1eddng \u0111i)\nfunc (dsu *DSU) Find(i int) int {\n\tif dsu.parent[i] == i {\n\t\treturn i\n\t}\n\t\/\/ \u0110\u1ec7 quy l\u00ean tr\u00ean, \u0111\u1ed3ng th\u1eddi c\u1eadp nh\u1eadt cha tr\u1ef1c ti\u1ebfp th\u00e0nh Root\n\tdsu.parent[i] = dsu.Find(dsu.parent[i])\n\treturn dsu.parent[i]\n}\n\n\/\/ H\u00e0m Union t\u00edch h\u1ee3p Union by Rank\nfunc (dsu *DSU) Union(i, j int) bool {\n\trootI := dsu.Find(i)\n\trootJ := dsu.Find(j)\n\n\tif rootI == rootJ {\n\t\treturn false \/\/ \u0110\u00e3 chung nh\u00f3m, n\u1ed1i th\u00eam s\u1ebd t\u1ea1o chu tr\u00ecnh\n\t}\n\n\t\/\/ G\u1eafn c\u00e2y l\u00f9n v\u00e0o d\u01b0\u1edbi c\u00e2y cao\n\tif dsu.rank[rootI] < dsu.rank[rootJ] {\n\t\tdsu.parent[rootI] = rootJ\n\t} else if dsu.rank[rootI] > dsu.rank[rootJ] {\n\t\tdsu.parent[rootJ] = rootI\n\t} else {\n\t\t\/\/ B\u1eb1ng nhau th\u00ec g\u1eafn b\u1eeba m\u1ed9t b\u00ean, v\u00e0 t\u0103ng chi\u1ec1u cao b\u00ean \u0111\u00f3 l\u00ean 1\n\t\tdsu.parent[rootJ] = rootI\n\t\tdsu.rank[rootI]++\n\t}\n\treturn true\n}\n\n\/\/ C\u1ea5u tr\u00fac m\u1ed9t C\u1ea1nh (Edge)\ntype Edge struct {\n\tU, V   int\n\tWeight int\n}\n\n\/\/ Thu\u1eadt to\u00e1n Kruskal t\u00ecm Minimum Spanning Tree\nfunc Kruskal(n int, edges []Edge) ([]Edge, int) {\n\t\/\/ 1. S\u1eafp x\u1ebfp c\u00e1c c\u1ea1nh t\u0103ng d\u1ea7n theo tr\u1ecdng s\u1ed1 (O(E log E))\n\tsort.Slice(edges, func(i, j int) bool {\n\t\treturn edges[i].Weight < edges[j].Weight\n\t})\n\n\tdsu := NewDSU(n)\n\tmst := []Edge{}\n\ttotalCost := 0\n\n\t\/\/ 2. Duy\u1ec7t qua c\u00e1c c\u1ea1nh\n\tfor _, edge := range edges {\n\t\t\/\/ N\u1ebfu Union th\u00e0nh c\u00f4ng (kh\u00f4ng t\u1ea1o chu tr\u00ecnh), ch\u1ecdn c\u1ea1nh n\u00e0y\n\t\tif dsu.Union(edge.U, edge.V) {\n\t\t\tmst = append(mst, edge)\n\t\t\ttotalCost += edge.Weight\n\n\t\t\t\/\/ \u0110\u00e3 \u0111\u1ee7 N-1 c\u1ea1nh th\u00ec d\u1eebng l\u1ea1i\n\t\t\tif len(mst) == n-1 {\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\treturn mst, totalCost\n}\n\nfunc main() {\n\t\/\/ Gi\u1ea3 l\u1eadp 5 nh\u00e0 ga (0 \u0111\u1ebfn 4)\n\tn := 5\n\tedges := []Edge{\n\t\t{0, 1, 10}, {0, 2, 6}, {0, 3, 5},\n\t\t{1, 3, 15}, {2, 3, 4}, {1, 4, 2}, {3, 4, 8},\n\t}\n\n\tfmt.Println(\"\u0110ang t\u00ednh to\u00e1n m\u1ea1ng c\u00e1p quang t\u1ed1i \u01b0u (MST)...\")\n\tmst, totalCost := Kruskal(n, edges)\n\n\tfmt.Printf(\"T\u1ed5ng chi ph\u00ed t\u1ed1i thi\u1ec3u: %d\\n\", totalCost)\n\tfmt.Println(\"C\u00e1c \u0111o\u1ea1n c\u00e1p c\u1ea7n tri\u1ec3n khai:\")\n\tfor _, e := range mst {\n\t\tfmt.Printf(\"Tr\u1ea1m %d <---> Tr\u1ea1m %d (Chi ph\u00ed: %d)\\n\", e.U, e.V, e.Weight)\n\t}\n}\n\n```\n\n## 6. Ph\u00e2n t\u00edch Hi\u1ec7u n\u0103ng (Big-O) v\u00e0 \u1ee8ng d\u1ee5ng Th\u1ef1c t\u1ebf\n\n-   **Th\u1eddi gian Kh\u1edfi t\u1ea1o DSU:** $O(N)$.\n    \n-   **Th\u1eddi gian Truy v\u1ea5n Find\/Union:** $O(\\alpha(N)) \\approx \\mathbf{O(1)}$.\n    \n-   **Th\u1eddi gian Kruskal:** **$O(E \\log E)$** do b\u1ecb chi ph\u1ed1i b\u1edfi b\u01b0\u1edbc s\u1eafp x\u1ebfp (Sort) danh s\u00e1ch c\u00e1c c\u1ea1nh ban \u0111\u1ea7u. B\u01b0\u1edbc duy\u1ec7t v\u00f2ng l\u1eb7p DSU c\u1ef1c k\u1ef3 nhanh $O(E \\cdot \\alpha(V))$.\n    \n-   **Kh\u00f4ng gian (Space):** $O(N)$ \u0111\u1ec3 l\u01b0u tr\u1eef 2 m\u1ea3ng `parent` v\u00e0 `rank` trong DSU.\n    \n\n**\u1ee8ng d\u1ee5ng c\u1ed1t l\u00f5i:**\n\n1.  **Thi\u1ebft k\u1ebf M\u1ea1ng l\u01b0\u1edbi V\u1eadt l\u00fd (Network Topology):** Kruskal l\u00e0 thu\u1eadt to\u00e1n ti\u00eau chu\u1ea9n \u0111\u1ec3 quy ho\u1ea1ch c\u00e1c tuy\u1ebfn c\u00e1p quang li\u00ean t\u1ec9nh, c\u00e1c tr\u1ea1m \u0111i\u1ec7n cao th\u1ebf, ho\u1eb7c h\u1ec7 th\u1ed1ng \u0111\u01b0\u1eddng \u1ed1ng n\u01b0\u1edbc sao cho t\u1ed5ng chi ph\u00ed l\u00e0 r\u1ebb nh\u1ea5t m\u00e0 v\u1eabn bao ph\u1ee7 to\u00e0n b\u1ed9 c\u00e1c n\u00fat.\n    \n2.  **Ph\u00e1t hi\u1ec7n Chu tr\u00ecnh (Cycle Detection):** DSU \u0111\u01b0\u1ee3c d\u00f9ng trong c\u00e1c b\u1ed9 bi\u00ean d\u1ecbch (Compilers) ho\u1eb7c h\u1ec7 th\u1ed1ng Dependency Injection (nh\u01b0 Service Container c\u1ee7a Laravel ho\u1eb7c Wire c\u1ee7a Golang) \u0111\u1ec3 ki\u1ec3m tra xem c\u00f3 module n\u00e0o \u0111ang ph\u1ee5 thu\u1ed9c v\u00f2ng tr\u00f2n l\u1eabn nhau (Circular Dependency) hay kh\u00f4ng.\n    \n3.  **Ph\u00e2n c\u1ee5m H\u00ecnh \u1ea3nh (Image Segmentation):** Ph\u00e2n chia c\u00e1c pixel l\u00e2n c\u1eadn c\u00f3 m\u00e0u s\u1eafc gi\u1ed1ng nhau th\u00e0nh c\u00e1c c\u1ee5m (Superpixels) trong x\u1eed l\u00fd \u1ea3nh y t\u1ebf ho\u1eb7c Machine Learning.\n    \n\nT\u1eeb m\u1ed9t c\u1ea5u tr\u00fac \u0111\u1ed3 th\u1ecb \u0111\u1ed9ng, n\u1ebfu ch\u00fang ta c\u1ea7n \u0111\u1ecbnh tuy\u1ebfn \u0111\u01b0\u1eddng \u0111i ng\u1eafn nh\u1ea5t kh\u00f4ng ch\u1ec9 v\u1edbi chi ph\u00ed r\u1ebb nh\u1ea5t, m\u00e0 c\u00f2n ph\u1ea3i t\u00ednh to\u00e1n qua h\u00e0ng tri\u1ec7u node tr\u00ean b\u1ea3n \u0111\u1ed3 th\u1ef1c t\u1ebf v\u1edbi s\u1ef1 tr\u1ee3 gi\u00fap c\u1ee7a \"Tr\u00ed tu\u1ec7 nh\u00e2n t\u1ea1o (Heuristic)\", ch\u00fang ta s\u1ebd ti\u1ebfn t\u1edbi thu\u1eadt to\u00e1n n\u1ec1n t\u1ea3ng c\u1ee7a m\u1ecdi \u1ee9ng d\u1ee5ng b\u1ea3n \u0111\u1ed3 hi\u1ec7n \u0111\u1ea1i.","published_at":"2026-10-25T09:43:11.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T16:53:03.000000Z","edited_at":"2026-10-08T00:36:52.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":7,"points":0,"views_count":10,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/8b112ae9-9a30-4c7c-89c2-59e1ce7e64d2.png","user":{"data":{"id":182653,"url":"https:\/\/viblo.asia\/u\/hhoang","avatar":"8392e404-ea43-497f-8b18-3777e24dc6ab.jpg","name":"Huy Ho\u00e0ng","username":"hhoang","followers_count":202,"reputation":14064,"posts_count":1576,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"cau-truc-du-lieu","name":"c\u1ea5u tr\u00fac d\u1eef li\u1ec7u"}]},"commentators":{"data":[]}},{"id":108493,"title":"C\u1ea5u tr\u00fac d\u1eef li\u1ec7u v\u00e0 Gi\u1ea3i thu\u1eadt B\u00e0i 84: Radix Tree (C\u00e2y c\u01a1 s\u1ed1) - N\u1ec1n t\u1ea3ng \u0111\u1ecbnh tuy\u1ebfn si\u00eau t\u1ed1c trong c\u00e1c HTTP Router hi\u1ec7n \u0111\u1ea1i.","slug":"gdJzvOvjJz5","url":"https:\/\/viblo.asia\/p\/cau-truc-du-lieu-va-giai-thuat-bai-84-radix-tree-cay-co-so-nen-tang-dinh-tuyen-sieu-toc-trong-cac-http-router-hien-dai-gdJzvOvjJz5","user_id":182653,"moderation":null,"transliterated":"cau-truc-du-lieu-va-giai-thuat-bai-84-radix-tree-cay-co-so-nen-tang-dinh-tuyen-sieu-toc-trong-cac-http-router-hien-dai","contents_short":"vi\u1ebft API b\u1eb1ng c\u00e1c framework nh\u01b0 Laravel (PHP), Express (Node.js) hay Gin\/Echo (Golang), b\u1ea1n th\u01b0\u1eddng \u0111\u1ecbnh ngh\u0129a h\u00e0ng ch\u1ee5c, th\u1eadm ch\u00ed h\u00e0ng tr\u0103m endpoints:\n\n-   GET \/api\/v1\/users\n\n-   GET \/api\/v1\/users\/:id\n\n-   POST \/api\/v1\/users\/:id\/orders\n\n-   GET \/api\/v1\/products\/search\n\nKhi m\u1ed9t HTTP Request bay v\u00e0o server v\u1edbi \u0111\u01b0\u1eddng d\u1eabn \/api\/v1\/users\/102\/orders, l\u00e0m sao framework bi\u1ebft ch\u00ednh x\u00e1c ph\u1ea3i g\u1ecdi \u0111\u1ebfn Contr...","contents":"vi\u1ebft API b\u1eb1ng c\u00e1c framework nh\u01b0 Laravel (PHP), Express (Node.js) hay Gin\/Echo (Golang), b\u1ea1n th\u01b0\u1eddng \u0111\u1ecbnh ngh\u0129a h\u00e0ng ch\u1ee5c, th\u1eadm ch\u00ed h\u00e0ng tr\u0103m endpoints:\n\n-   `GET \/api\/v1\/users`\n    \n-   `GET \/api\/v1\/users\/:id`\n    \n-   `POST \/api\/v1\/users\/:id\/orders`\n    \n-   `GET \/api\/v1\/products\/search`\n    \n\nKhi m\u1ed9t HTTP Request bay v\u00e0o server v\u1edbi \u0111\u01b0\u1eddng d\u1eabn `\/api\/v1\/users\/102\/orders`, l\u00e0m sao framework bi\u1ebft ch\u00ednh x\u00e1c ph\u1ea3i g\u1ecdi \u0111\u1ebfn Controller hay Closure (Handler) n\u00e0o?\n\nN\u1ebfu d\u00f9ng m\u1ed9t m\u1ea3ng (Array) ch\u1ee9a c\u00e1c Regex (Bi\u1ec3u th\u1ee9c ch\u00ednh quy) v\u00e0 qu\u00e9t tu\u1ea7n t\u1ef1 t\u1eeb tr\u00ean xu\u1ed1ng d\u01b0\u1edbi, h\u1ec7 th\u1ed1ng s\u1ebd ch\u1eadm d\u1ea7n khi s\u1ed1 l\u01b0\u1ee3ng API t\u0103ng l\u00ean (\u0111\u1ed9 ph\u1ee9c t\u1ea1p $O(N)$). \u0110\u1ec3 \u0111\u1ea1t t\u1ed1c \u0111\u1ed9 truy xu\u1ea5t $O(K)$ (v\u1edbi $K$ l\u00e0 \u0111\u1ed9 d\u00e0i c\u1ee7a URL) \u2014 kh\u00f4ng b\u1ecb \u1ea3nh h\u01b0\u1edfng b\u1edfi s\u1ed1 l\u01b0\u1ee3ng API trong h\u1ec7 th\u1ed1ng \u2014 c\u00e1c framework hi\u1ec7n \u0111\u1ea1i s\u1eed d\u1ee5ng m\u1ed9t phi\u00ean b\u1ea3n n\u00e9n c\u1ee7a C\u00e2y Trie (B\u00e0i 52) mang t\u00ean **Radix Tree** (C\u00e2y c\u01a1 s\u1ed1, hay c\u00f2n g\u1ecdi l\u00e0 Patricia Trie).\n\n## 1. N\u1ed7i \u0111au c\u1ee7a Standard Trie v\u00e0 S\u1ef1 ra \u0111\u1eddi c\u1ee7a Radix Tree\n\nTrong m\u1ed9t Standard Trie (C\u00e2y ti\u1ec1n t\u1ed1 c\u01a1 b\u1ea3n), m\u1ed7i Node ch\u1ec9 l\u01b0u tr\u1eef **\u0111\u00fang 1 k\u00fd t\u1ef1**.\n\nN\u1ebfu b\u1ea1n ch\u00e8n 2 chu\u1ed7i `\/api\/v1\/users` v\u00e0 `\/api\/v1\/posts`, Trie s\u1ebd t\u1ea1o ra h\u00e0ng lo\u1ea1t c\u00e1c Node n\u1ed1i \u0111u\u00f4i nhau m\u1ed9t c\u00e1ch v\u00f4 ngh\u0129a:\n\n`(Root) -> \/ -> a -> p -> i -> \/ -> v -> 1 -> \/ -> ...`\n\nVi\u1ec7c t\u1ea1o ra 10 Node li\u00ean ti\u1ebfp ch\u1ec9 c\u00f3 \u0111\u00fang 1 nh\u00e1nh con (Single-child nodes) g\u00e2y ra hai v\u1ea5n \u0111\u1ec1:\n\n1.  **L\u00e3ng ph\u00ed RAM tr\u1ea7m tr\u1ecdng:** H\u00e0ng ng\u00e0n Node \u0111\u01b0\u1ee3c t\u1ea1o ra ch\u1ec9 \u0111\u1ec3 ch\u1ee9a c\u00e1c k\u00fd t\u1ef1 tr\u00f9ng l\u1eb7p.\n    \n2.  **Ch\u1eadm ch\u1ea1p (Cache Miss):** C\u1ee9 \u0111\u1ecdc 1 k\u00fd t\u1ef1 l\u1ea1i ph\u1ea3i nh\u1ea3y con tr\u1ecf sang v\u00f9ng nh\u1edb kh\u00e1c tr\u00ean RAM.\n    \n\n**Radix Tree gi\u1ea3i quy\u1ebft b\u1eb1ng c\u01a1 ch\u1ebf N\u00e9n (Compression):**\n\nB\u1ea5t k\u1ef3 chu\u1ed7i Node n\u00e0o c\u00f3 duy nh\u1ea5t m\u1ed9t nh\u00e1nh con k\u00e9o d\u00e0i s\u1ebd \u0111\u01b0\u1ee3c **g\u1ed9p l\u1ea1i (Merge) th\u00e0nh m\u1ed9t Node duy nh\u1ea5t ch\u1ee9a m\u1ed9t chu\u1ed7i k\u00fd t\u1ef1 (String\/Edge Label)**.\n\nV\u00ed d\u1ee5, v\u1edbi 2 route tr\u00ean, Radix Tree s\u1ebd ch\u1ec9 c\u00f3:\n\n-   Root Node ch\u1ee9a: `\/api\/v1\/`\n    \n-   R\u1ebd nh\u00e1nh 1: `users`\n    \n-   R\u1ebd nh\u00e1nh 2: `posts`\n    \n\nNh\u1edd vi\u1ec7c g\u1ed9p n\u00e0y, c\u1ea5u tr\u00fac c\u00e2y tr\u1edf n\u00ean c\u1ef1c k\u1ef3 n\u00f4ng (shallow), ti\u1ebft ki\u1ec7m 80% RAM v\u00e0 t\u0103ng t\u1ed1c \u0111\u1ed9 duy\u1ec7t nh\u1edd c\u01a1 ch\u1ebf \u0111\u1ed1i chi\u1ebfu m\u1ed9t l\u00fac nhi\u1ec1u k\u00fd t\u1ef1 thay v\u00ec t\u1eebng k\u00fd t\u1ef1 \u0111\u01a1n l\u1ebb.\n\n## 2. B\u1eaft c\u00e1c Bi\u1ebfn \u0111\u1ed9ng (Dynamic Parameters) v\u00e0 Wildcards\n\nHTTP Router kh\u00f4ng ch\u1ec9 c\u00f3 c\u00e1c chu\u1ed7i t\u0129nh (Static Routes) m\u00e0 c\u00f2n c\u00f3 c\u00e1c bi\u1ebfn \u0111\u1ed9ng (Parametric Routes) nh\u01b0 `:id`.\n\n\u0110\u1ec3 h\u1ed7 tr\u1ee3 \u0111i\u1ec1u n\u00e0y, m\u1ed7i Node trong Radix Tree c\u1ee7a m\u1ed9t Router th\u01b0\u1eddng \u0111\u01b0\u1ee3c ph\u00e2n lo\u1ea1i (NodeType):\n\n-   **Static Node:** Kh\u1edbp ch\u00ednh x\u00e1c chu\u1ed7i (VD: `\/users\/`).\n    \n-   **Param Node:** Kh\u1edbp m\u1ed9t ph\u00e2n \u0111o\u1ea1n \u0111\u1ed9ng, d\u1eebng l\u1ea1i khi g\u1eb7p d\u1ea5u `\/` ti\u1ebfp theo (VD: `:id`).\n    \n-   **Catch-all \/ Wildcard Node:** Kh\u1edbp to\u00e0n b\u1ed9 ph\u1ea7n \u0111u\u00f4i c\u00f2n l\u1ea1i c\u1ee7a URL (VD: `*filepath`).\n    \n\nKhi r\u1ebd nh\u00e1nh, thu\u1eadt to\u00e1n t\u00ecm ki\u1ebfm tr\u00ean Radix Tree s\u1ebd lu\u00f4n **\u01b0u ti\u00ean Static Node tr\u01b0\u1edbc**. N\u1ebfu kh\u00f4ng t\u00ecm th\u1ea5y, n\u00f3 s\u1ebd l\u00f9i l\u1ea1i (Backtrack) v\u00e0 th\u1eed \u0111i v\u00e0o Param Node. C\u01a1 ch\u1ebf n\u00e0y \u0111\u1ea3m b\u1ea3o `\/users\/search` s\u1ebd g\u1ecdi \u0111\u00fang h\u00e0m t\u00ecm ki\u1ebfm, thay v\u00ec hi\u1ec3u nh\u1ea7m ch\u1eef `search` th\u00e0nh `:id` trong `\/users\/:id`.\n\n## 3. Tri\u1ec3n khai Radix Tree Router si\u00eau t\u1ed1c b\u1eb1ng Golang\n\nH\u1ec7 sinh th\u00e1i Golang n\u1ed5i ti\u1ebfng v\u1edbi hi\u1ec7u n\u0103ng cao, v\u00e0 package `julienschmidt\/httprouter` hay `gin-gonic\/gin` \u0111\u1ec1u s\u1eed d\u1ee5ng Radix Tree l\u00e0m l\u00f5i.\n\nD\u01b0\u1edbi \u0111\u00e2y l\u00e0 phi\u00ean b\u1ea3n minh h\u1ecda (\u0111\u00e3 \u0111\u01a1n gi\u1ea3n h\u00f3a) c\u00e1ch m\u1ed9t Radix Tree ch\u00e8n URL t\u0129nh v\u00e0 n\u00e9n chu\u1ed7i:\n\nGo\n\n```\npackage main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n\/\/ C\u1ea5u tr\u00fac m\u1ed9t Node trong Radix Tree\ntype RadixNode struct {\n\tpath     string       \/\/ Chu\u1ed7i k\u00fd t\u1ef1 (Edge label) \u0111\u00e3 \u0111\u01b0\u1ee3c n\u00e9n\n\thandler  string       \/\/ T\u00ean c\u1ee7a Controller (N\u1ebfu l\u00e0 \u0111i\u1ec3m k\u1ebft th\u00fac c\u1ee7a m\u1ed9t Route)\n\tchildren []*RadixNode \/\/ C\u00e1c nh\u00e1nh con\n}\n\ntype RadixTree struct {\n\troot *RadixNode\n}\n\nfunc NewRadixTree() *RadixTree {\n\treturn &RadixTree{\n\t\troot: &RadixNode{path: \"\"},\n\t}\n}\n\n\/\/ H\u00e0m t\u00ecm \u0111\u1ed9 d\u00e0i ti\u1ec1n t\u1ed1 chung (Longest Common Prefix) gi\u1eefa 2 chu\u1ed7i\nfunc longestCommonPrefix(a, b string) int {\n\ti := 0\n\tmax := len(a)\n\tif len(b) < max {\n\t\tmax = len(b)\n\t}\n\tfor i < max && a[i] == b[i] {\n\t\ti++\n\t}\n\treturn i\n}\n\n\/\/ Th\u00eam Route m\u1edbi v\u00e0o Radix Tree\nfunc (rt *RadixTree) Insert(path string, handler string) {\n\tnode := rt.root\n\tsearch := path\n\n\tfor {\n\t\tif len(search) == 0 {\n\t\t\tnode.handler = handler\n\t\t\treturn\n\t\t}\n\n\t\t\/\/ T\u00ecm xem c\u00f3 nh\u00e1nh con n\u00e0o b\u1eaft \u0111\u1ea7u b\u1eb1ng k\u00fd t\u1ef1 \u0111\u1ea7u ti\u00ean c\u1ee7a 'search' kh\u00f4ng\n\t\tvar matchChild *RadixNode\n\t\tfor _, child := range node.children {\n\t\t\tif child.path[0] == search[0] {\n\t\t\t\tmatchChild = child\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\t\/\/ N\u1ebfu kh\u00f4ng c\u00f3 nh\u00e1nh n\u00e0o kh\u1edbp, t\u1ea1o th\u1eb3ng m\u1ed9t Node m\u1edbi ch\u1ee9a to\u00e0n b\u1ed9 ph\u1ea7n c\u00f2n l\u1ea1i\n\t\tif matchChild == nil {\n\t\t\tnewNode := &RadixNode{\n\t\t\t\tpath:    search,\n\t\t\t\thandler: handler,\n\t\t\t}\n\t\t\tnode.children = append(node.children, newNode)\n\t\t\treturn\n\t\t}\n\n\t\t\/\/ T\u00ecm ti\u1ec1n t\u1ed1 chung gi\u1eefa 'search' v\u00e0 \u0111\u01b0\u1eddng d\u1eabn c\u1ee7a nh\u00e1nh con\n\t\tcommonPrefixLen := longestCommonPrefix(search, matchChild.path)\n\n\t\t\/\/ 1. N\u1ebfu ti\u1ec1n t\u1ed1 chung ng\u1eafn h\u01a1n path c\u1ee7a matchChild -> B\u1eaft bu\u1ed9c ph\u1ea3i T\u00c1CH (Split) Node\n\t\tif commonPrefixLen < len(matchChild.path) {\n\t\t\t\/\/ Ph\u1ea7n b\u1ecb t\u00e1ch r\u1eddi (\u0111\u1ea9y xu\u1ed1ng l\u00e0m con)\n\t\t\tsplitNode := &RadixNode{\n\t\t\t\tpath:     matchChild.path[commonPrefixLen:],\n\t\t\t\thandler:  matchChild.handler,\n\t\t\t\tchildren: matchChild.children, \/\/ K\u1ebf th\u1eeba to\u00e0n b\u1ed9 con c\u0169\n\t\t\t}\n\n\t\t\t\/\/ C\u1eadp nh\u1eadt l\u1ea1i Node hi\u1ec7n t\u1ea1i\n\t\t\tmatchChild.path = matchChild.path[:commonPrefixLen]\n\t\t\tmatchChild.children = []*RadixNode{splitNode}\n\t\t\tmatchChild.handler = \"\" \/\/ N\u01a1i b\u1ecb t\u00e1ch kh\u00f4ng c\u00f2n l\u00e0 \u0111i\u1ec3m k\u1ebft th\u00fac c\u0169\n\t\t}\n\n\t\t\/\/ 2. C\u1eaft b\u1ecf ph\u1ea7n \u0111\u00e3 kh\u1edbp ra kh\u1ecfi 'search', chu\u1ea9n b\u1ecb cho v\u00f2ng l\u1eb7p ti\u1ebfp theo \u0111i xu\u1ed1ng s\u00e2u h\u01a1n\n\t\tif commonPrefixLen < len(search) {\n\t\t\tsearch = search[commonPrefixLen:]\n\t\t\tnode = matchChild\n\t\t} else {\n\t\t\t\/\/ Kh\u1edbp ho\u00e0n to\u00e0n, c\u1eadp nh\u1eadt Handler t\u1ea1i \u0111\u00e2y\n\t\t\tmatchChild.handler = handler\n\t\t\treturn\n\t\t}\n\t}\n}\n\n\/\/ T\u00ecm ki\u1ebfm Route\nfunc (rt *RadixTree) Search(path string) string {\n\tnode := rt.root\n\tsearch := path\n\n\tfor len(search) > 0 {\n\t\tvar matchChild *RadixNode\n\t\tfor _, child := range node.children {\n\t\t\tif strings.HasPrefix(search, child.path) {\n\t\t\t\tmatchChild = child\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif matchChild == nil {\n\t\t\treturn \"404 Not Found\"\n\t\t}\n\n\t\tsearch = search[len(matchChild.path):]\n\t\tnode = matchChild\n\t}\n\n\tif node.handler != \"\" {\n\t\treturn node.handler\n\t}\n\treturn \"404 Not Found\"\n}\n\nfunc main() {\n\trouter := NewRadixTree()\n\t\n\t\/\/ Khai b\u00e1o c\u00e1c Routes\n\trouter.Insert(\"\/api\/v1\/users\", \"UserController@Index\")\n\trouter.Insert(\"\/api\/v1\/users\/active\", \"UserController@Active\")\n\trouter.Insert(\"\/api\/v1\/posts\", \"PostController@Index\")\n\n\t\/\/ Truy v\u1ea5n th\u1eed nghi\u1ec7m\n\tfmt.Println(\"GET \/api\/v1\/users ->\", router.Search(\"\/api\/v1\/users\"))\n\tfmt.Println(\"GET \/api\/v1\/users\/active ->\", router.Search(\"\/api\/v1\/users\/active\"))\n\tfmt.Println(\"GET \/api\/v1\/posts ->\", router.Search(\"\/api\/v1\/posts\"))\n\tfmt.Println(\"GET \/api\/v1\/comments ->\", router.Search(\"\/api\/v1\/comments\")) \/\/ Kh\u00f4ng t\u1ed3n t\u1ea1i\n}\n\n```\n\n## 4. Ph\u00e2n t\u00edch Hi\u1ec7u n\u0103ng v\u00e0 \u1ee8ng d\u1ee5ng Th\u1ef1c t\u1ebf\n\n-   **Th\u1eddi gian Truy v\u1ea5n (Routing Time):** **$O(K)$** (v\u1edbi $K$ l\u00e0 \u0111\u1ed9 d\u00e0i chu\u1ed7i URL). Vi\u1ec7c \u0111\u1ecbnh tuy\u1ebfn kh\u00f4ng t\u1ed1n m\u1ed9t ch\u00fat RAM c\u1ea5p ph\u00e1t (Zero Memory Allocation) n\u00e0o v\u00e0 ch\u1ea1y ho\u00e0n to\u00e0n tr\u00ean CPU Cache. Framework Gin c\u1ee7a Golang n\u1ed5i ti\u1ebfng c\u00f3 th\u1ec3 \u0111\u1ecbnh tuy\u1ebfn h\u00e0ng v\u1ea1n request m\u1ed7i gi\u00e2y m\u00e0 kh\u00f4ng sinh ra Garbage Collection d\u01b0 th\u1eeba.\n    \n-   **Kh\u00f4ng gian (Space):** Nh\u1ecf h\u01a1n Standard Trie r\u1ea5t nhi\u1ec1u l\u1ea7n nh\u1edd n\u00e9n c\u00e1c \u0111\u01b0\u1eddng \u0111i li\u00ean t\u1ee5c, cho ph\u00e9p load h\u00e0ng ngh\u00ecn endpoint l\u00ean RAM m\u1ed9t c\u00e1ch g\u1ecdn nh\u1eb9.\n    \n\n**\u1ee8ng d\u1ee5ng c\u1ed1t l\u00f5i:**\n\nB\u00ean c\u1ea1nh HTTP Router (nh\u01b0 Gin, Echo, Fiber trong Golang), Radix Tree c\u00f2n l\u00e0 tr\u00e1i tim c\u1ee7a c\u00e1c h\u1ec7 th\u1ed1ng m\u1ea1ng quan tr\u1ecdng:\n\n-   **IP Routing (Tra c\u1ee9u B\u1ea3ng \u0111\u1ecbnh tuy\u1ebfn):** C\u00e1c Router ph\u1ea7n c\u1ee9ng c\u1ee7a Cisco ho\u1eb7c Juniper s\u1eed d\u1ee5ng m\u1ed9t bi\u1ebfn th\u1ec3 g\u1ecdi l\u00e0 Patricia Trie \u0111\u1ec3 t\u00ecm ki\u1ebfm Longest Prefix Match (Ti\u1ec1n t\u1ed1 chung d\u00e0i nh\u1ea5t) cho c\u00e1c d\u1ea3i \u0111\u1ecba ch\u1ec9 IP (CIDR), gi\u00fap chuy\u1ec3n ti\u1ebfp g\u00f3i tin (Packet Forwarding) \u1edf t\u1ed1c \u0111\u1ed9 h\u00e0ng Terabits\/s.\n    \n-   **H\u1ec7 th\u1ed1ng Cache & Key-Value Stores:** B\u1ea5t k\u1ef3 n\u01a1i n\u00e0o c\u00f3 Kh\u00f3a (Key) l\u00e0 chu\u1ed7i v\u00e0 c\u00f3 nhi\u1ec1u ti\u1ec1n t\u1ed1 chung gi\u1ed1ng nhau, Radix Tree lu\u00f4n l\u00e0 m\u1ed9t gi\u1ea3i ph\u00e1p t\u1ed1i \u01b0u RAM v\u00e0 t\u1ed1c \u0111\u1ed9 \u0111\u00e1ng c\u00e2n nh\u1eafc so v\u1edbi Hash Map th\u00f4ng th\u01b0\u1eddng.","published_at":"2026-10-25T09:43:03.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T16:52:03.000000Z","edited_at":"2026-10-08T00:34:37.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":5,"points":0,"views_count":9,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/ed0c681e-290a-4ca4-9171-546a50af7d8f.png","user":{"data":{"id":182653,"url":"https:\/\/viblo.asia\/u\/hhoang","avatar":"8392e404-ea43-497f-8b18-3777e24dc6ab.jpg","name":"Huy Ho\u00e0ng","username":"hhoang","followers_count":202,"reputation":14064,"posts_count":1576,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"cau-truc-du-lieu","name":"c\u1ea5u tr\u00fac d\u1eef li\u1ec7u"}]},"commentators":{"data":[]}},{"id":109661,"title":"\u0110\u1ed3ng b\u1ed9 hreflang cho site t\u0129nh 13 ng\u00f4n ng\u1eef khi b\u1ea3n d\u1ecbch c\u00f2n vi\u1ebft d\u1edf: lo\u1ea1i file ch\u01b0a commit b\u1eb1ng git","slug":"yZJZlRrGVjm","url":"https:\/\/viblo.asia\/p\/dong-bo-hreflang-cho-site-tinh-13-ngon-ngu-khi-ban-dich-con-viet-do-loai-file-chua-commit-bang-git-yZJZlRrGVjm","user_id":226329,"moderation":null,"transliterated":"dong-bo-hreflang-cho-site-tinh-13-ngon-ngu-khi-ban-dich-con-viet-do-loai-file-chua-commit-bang-git","contents_short":"M\u00ecnh l\u00e0 Ayumu Kitabayashi, ng\u01b0\u1eddi ph\u00e1t tri\u1ec3n \u1ee9ng d\u1ee5ng iPhone minulo. Trang web c\u1ee7a app (minulo.app) l\u00e0 site t\u0129nh vi\u1ebft tay b\u1eb1ng HTML, c\u00f3 13 ng\u00f4n ng\u1eef, ch\u1ea1y tr\u00ean GitHub Pages. Kh\u00f4ng c\u00f3 framework, kh\u00f4ng c\u00f3 b\u01b0\u1edbc build.\n\n\u1ede b\u00e0i tr\u01b0\u1edbc m\u00ecnh \u0111\u00e3 gi\u1edbi thi\u1ec7u script tools\/sync_langs.py: n\u00f3 xem file n\u00e0o th\u1ef1c s\u1ef1 c\u00f3 trong t\u1eebng th\u01b0 m\u1ee5c ng\u00f4n ng\u1eef, r\u1ed3i d\u1ef1ng l\u1ea1i th\u1ebb hreflang, kh\u1ed1i ch\u1ecdn ng\u00f4n ng\u1eef \u1edf footer v\u00e0 c\u00e1c d\u00f2ng a...","contents":"M\u00ecnh l\u00e0 Ayumu Kitabayashi, ng\u01b0\u1eddi ph\u00e1t tri\u1ec3n \u1ee9ng d\u1ee5ng iPhone minulo. Trang web c\u1ee7a app (minulo.app) l\u00e0 site t\u0129nh vi\u1ebft tay b\u1eb1ng HTML, c\u00f3 13 ng\u00f4n ng\u1eef, ch\u1ea1y tr\u00ean GitHub Pages. Kh\u00f4ng c\u00f3 framework, kh\u00f4ng c\u00f3 b\u01b0\u1edbc build.\n\n\u1ede [b\u00e0i tr\u01b0\u1edbc](https:\/\/viblo.asia\/p\/hreflang-cho-website-tinh-13-ngon-ngu-dung-lai-tu-cac-file-thuc-su-ton-tai-thay-vi-sua-tay-AoJe8jGD41j) m\u00ecnh \u0111\u00e3 gi\u1edbi thi\u1ec7u script `tools\/sync_langs.py`: n\u00f3 xem file n\u00e0o th\u1ef1c s\u1ef1 c\u00f3 trong t\u1eebng th\u01b0 m\u1ee5c ng\u00f4n ng\u1eef, r\u1ed3i d\u1ef1ng l\u1ea1i th\u1ebb hreflang, kh\u1ed1i ch\u1ecdn ng\u00f4n ng\u1eef \u1edf footer v\u00e0 c\u00e1c d\u00f2ng alternate trong sitemap. B\u00e0i n\u00e0y kh\u00f4ng nh\u1eafc l\u1ea1i c\u00e1ch script \u0111\u00f3 ho\u1ea1t \u0111\u1ed9ng. M\u00ecnh vi\u1ebft v\u1ec1 l\u1ed7i ph\u00e1t sinh khi d\u00f9ng n\u00f3 trong l\u00fac nhi\u1ec1u \u0111\u1ee3t d\u1ecbch ch\u1ea1y song song, v\u00e0 c\u00e1ch m\u00ecnh x\u1eed l\u00fd m\u00e0 kh\u00f4ng ph\u1ea3i s\u1eeda script g\u1ed1c.\n\n## L\u1ed7i x\u1ea3y ra nh\u01b0 th\u1ebf n\u00e0o\n\nM\u00ecnh d\u1ecbch b\u00e0i m\u1edbi theo t\u1eebng nh\u00f3m ng\u00f4n ng\u1eef. V\u00e0i commit g\u1ea7n \u0111\u00e2y tr\u00ean repo:\n\n- 16 trang ti\u1ebfng \u00dd v\u00e0 ti\u1ebfng Indonesia\n- 18 trang ti\u1ebfng Vi\u1ec7t v\u00e0 ti\u1ebfng Nga\n- 17 trang ti\u1ebfng Trung ph\u1ed3n th\u1ec3 v\u00e0 ti\u1ebfng Th\u00e1i\n- 40 trang ti\u1ebfng \u0110\u1ee9c, Ph\u00e1p, T\u00e2y Ban Nha v\u00e0 B\u1ed3 \u0110\u00e0o Nha\n- c\u00f3 m\u1ed9t commit g\u1ed9p nhi\u1ec1u \u0111\u1ee3t, t\u1ed5ng c\u1ed9ng 69 trang\n\nC\u00e1c \u0111\u1ee3t n\u00e0y kh\u00f4ng ch\u1edd nhau. Khi nh\u00f3m ti\u1ebfng \u00dd \u0111\u00e3 xong v\u00e0 c\u1ea7n commit th\u00ec trong `de\/`, `fr\/` c\u00f3 th\u1ec3 \u0111\u00e3 c\u00f3 file ti\u1ebfng \u0110\u1ee9c, ti\u1ebfng Ph\u00e1p m\u1edbi d\u1ecbch \u0111\u01b0\u1ee3c m\u1ed9t n\u1eeda. Nh\u1eefng file \u0111\u00f3 ch\u01b0a `git add`, ngh\u0129a l\u00e0 \u0111ang \u1edf tr\u1ea1ng th\u00e1i untracked.\n\nTrong khi \u0111\u00f3 sync_langs.py quy\u1ebft \u0111\u1ecbnh \"trang n\u00e0y c\u00f3 b\u1ea3n ng\u00f4n ng\u1eef n\u00e0o\" ch\u1ec9 b\u1eb1ng m\u1ed9t d\u00f2ng:\n\n```python\nhave=[(h,d,n) for h,d,n in L if os.path.exists(path(d,s))]\n```\n\n`os.path.exists` kh\u00f4ng ph\u00e2n bi\u1ec7t file \u0111\u00e3 xong hay \u0111ang vi\u1ebft d\u1edf. Ch\u1ea1y sync cho slug `abc.html` th\u00ec file `de\/abc.html` d\u1edf dang c\u0169ng \u0111\u01b0\u1ee3c \u0111\u01b0a v\u00e0o hreflang v\u00e0 footer c\u1ee7a t\u1ea5t c\u1ea3 c\u00e1c b\u1ea3n ng\u00f4n ng\u1eef kh\u00e1c. C\u00e1c file \u0111\u00f3 \u0111\u01b0\u1ee3c commit v\u00e0 push, c\u00f2n `de\/abc.html` th\u00ec kh\u00f4ng. K\u1ebft qu\u1ea3: tr\u00ean site th\u1eadt c\u00f3 link tr\u1ecf t\u1edbi trang ch\u01b0a t\u1ed3n t\u1ea1i.\n\n## \u00dd t\u01b0\u1edfng: d\u00f9ng git \u0111\u1ec3 bi\u1ebft file n\u00e0o \"ch\u01b0a c\u00f3\"\n\nTh\u00f4ng tin \"file n\u00e0o \u0111\u00e3 xong\" th\u1eadt ra \u0111\u00e3 c\u00f3 s\u1eb5n trong git. File \u0111\u00e3 commit, ho\u1eb7c file m\u00ecnh ch\u1ee7 \u0111\u1ed9ng \u0111\u01b0a v\u00e0o danh s\u00e1ch c\u1ee7a \u0111\u1ee3t n\u00e0y, l\u00e0 file \u0111\u00e3 xong. File untracked c\u00f2n l\u1ea1i l\u00e0 vi\u1ec7c \u0111ang l\u00e0m d\u1edf.\n\nM\u00ecnh vi\u1ebft m\u1ed9t script b\u1ecdc ngo\u00e0i l\u00e0 `integ_tr.py`. N\u00f3 nh\u1eadn v\u00e0o `newfiles.txt` (danh s\u00e1ch file m\u1edbi c\u1ee7a \u0111\u1ee3t n\u00e0y) v\u00e0 l\u1ea5y danh s\u00e1ch untracked t\u1eeb git:\n\n```python\nuntracked=subprocess.run(['git','ls-files','--others','--exclude-standard'],\n                         capture_output=True,text=True).stdout.split()\nopen(J+'\/th_excl.txt','w').write('\\n'.join(u for u in untracked if u not in new))\n```\n\n`th_excl.txt` ch\u1ee9a nh\u1eefng file c\u1ea7n coi nh\u01b0 kh\u00f4ng t\u1ed3n t\u1ea1i trong l\u1ea7n ch\u1ea1y n\u00e0y.\n\n## Kh\u00f4ng s\u1eeda sync_langs.py, m\u00e0 t\u1ea1o m\u1ed9t b\u1ea3n sao \u0111\u00e3 v\u00e1\n\nM\u00ecnh mu\u1ed1n sync_langs.py v\u1eabn ch\u1ea1y \u0111\u01b0\u1ee3c m\u1ed9t m\u00ecnh nh\u01b0 tr\u01b0\u1edbc, n\u00ean kh\u00f4ng th\u00eam tham s\u1ed1 hay ch\u1ebf \u0111\u1ed9 m\u1edbi v\u00e0o n\u00f3. Thay v\u00e0o \u0111\u00f3, `integ_tr.py` \u0111\u1ecdc m\u00e3 ngu\u1ed3n c\u1ee7a n\u00f3, thay hai ch\u1ed7 b\u1eb1ng `str.replace`, r\u1ed3i ghi ra m\u1ed9t file t\u1ea1m `sync_ex.py`:\n\n```python\nsrc=open('tools\/sync_langs.py').read() \\\n  .replace(\"ROOT=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\",\n           \"ROOT='%s'\\nEX=set(os.path.join(ROOT,l.strip()) for l in open('%s\/th_excl.txt') if l.strip())\"%(R,J)) \\\n  .replace(\"os.path.exists(path(d,s))\",\n           \"(os.path.exists(path(d,s)) and path(d,s) not in EX)\")\nopen(J+'\/sync_ex.py','w').write(src)\n```\n\nCh\u1ed7 thay th\u1ee9 nh\u1ea5t c\u1ea7n thi\u1ebft v\u00ec b\u1ea3n sao n\u1eb1m trong th\u01b0 m\u1ee5c t\u1ea1m, `__file__` kh\u00f4ng c\u00f2n tr\u1ecf v\u1ec1 repo n\u00ean `ROOT` ph\u1ea3i ghi c\u1ee9ng. \u0110\u1ed3ng th\u1eddi n\u1ea1p t\u1eadp `EX` t\u1eeb `th_excl.txt`. Ch\u1ed7 thay th\u1ee9 hai th\u00eam \u0111i\u1ec1u ki\u1ec7n \"kh\u00f4ng n\u1eb1m trong EX\" v\u00e0o ph\u00e9p ki\u1ec3m tra t\u1ed3n t\u1ea1i.\n\nSau \u0111\u00f3 ch\u1ea1y b\u1ea3n sao cho t\u1eebng slug c\u1ee7a \u0111\u1ee3t n\u00e0y:\n\n```python\nslugs=sorted(set(os.path.basename(p) for p in new))\nfor s in slugs: subprocess.run(['python3',J+'\/sync_ex.py',s],check=True,capture_output=True)\n```\n\nM\u1ed9t \u0111i\u1ec3m c\u1ea7n bi\u1ebft khi v\u00e1 ki\u1ec3u n\u00e0y: n\u1ebfu sau n\u00e0y m\u00ecnh s\u1eeda \u0111\u00fang d\u00f2ng `os.path.exists(path(d,s))` trong sync_langs.py th\u00ec `replace` s\u1ebd kh\u00f4ng kh\u1edbp v\u00e0 c\u0169ng kh\u00f4ng b\u00e1o l\u1ed7i. B\u1ea3n sao v\u1eabn ch\u1ea1y, ch\u1ec9 l\u00e0 kh\u00f4ng lo\u1ea1i file n\u00e0o. V\u00ec v\u1eady m\u00ecnh kh\u00f4ng ch\u1ec9 d\u1ef1a v\u00e0o b\u01b0\u1edbc n\u00e0y m\u00e0 c\u00f2n c\u00f3 b\u01b0\u1edbc ki\u1ec3m tra \u1edf d\u01b0\u1edbi.\n\n## Ki\u1ec3m tra tr\u01b0\u1edbc khi commit: link n\u00e0o c\u0169ng ph\u1ea3i c\u00f3 trong git\n\nTr\u01b0\u1edbc khi `git add`, script \u0111i qua t\u1eebng file HTML s\u1ebd commit v\u00e0 ki\u1ec3m tra m\u1ecdi link t\u01b0\u01a1ng \u0111\u1ed1i t\u1edbi `.html`. \u0110\u00edch c\u1ee7a link ph\u1ea3i l\u00e0 file \u0111\u00e3 \u0111\u01b0\u1ee3c git theo d\u00f5i, ho\u1eb7c l\u00e0 file m\u1edbi c\u1ee7a \u0111\u1ee3t n\u00e0y:\n\n```python\ntracked=set(subprocess.run(['git','ls-files'],capture_output=True,\n                           text=True).stdout.split())|set(new)\nfor h in re.findall(r'href=\"([^\"#?:]+\\.html)',x):\n    q=os.path.normpath(os.path.join(os.path.dirname(p),h))\n    if q not in tracked: print('bad link',p,h); bad+=1\n```\n\nC\u00f9ng v\u00f2ng l\u1eb7p \u0111\u00f3, c\u00e1c kh\u1ed1i `<script type=\"application\/ld+json\">` \u0111\u01b0\u1ee3c \u0111\u01b0a qua `json.loads`. JSON-LD h\u1ecfng th\u00ec script d\u1eebng lu\u00f4n ch\u1ee9 kh\u00f4ng ch\u1ec9 in c\u1ea3nh b\u00e1o.\n\nB\u01b0\u1edbc n\u00e0y kh\u00f4ng quan t\u00e2m link sinh ra t\u1eeb \u0111\u00e2u (sync, hay m\u00ecnh t\u1ef1 g\u00f5 khi d\u1ecbch). Ch\u1ec9 c\u1ea7n c\u00f3 link t\u1edbi trang ch\u01b0a v\u00e0o git l\u00e0 kh\u00f4ng commit.\n\n## Ki\u1ec3m tra tr\u00f9ng l\u1eb7p trong sitemap\n\n```python\nlocs=re.findall(r'<loc>([^<]*)<\/loc>',open('sitemap.xml').read())\nif len(locs)!=len(set(locs)): print('DUP'); bad+=1\nif bad: sys.exit('abort')\n```\n\nKi\u1ec3m tra n\u00e0y c\u00f3 l\u00fd do c\u1ee5 th\u1ec3. sync_langs.py x\u00f3a `<url>` c\u0169 c\u1ee7a slug r\u1ed3i ch\u00e8n l\u1ea1i \u1edf cu\u1ed1i sitemap. Nh\u01b0ng regex x\u00f3a kh\u00f4ng kh\u1edbp v\u1edbi c\u00e1c m\u1ee5c vi\u1ebft theo \u0111\u1ecbnh d\u1ea1ng c\u0169, n\u00ean nh\u1eefng m\u1ee5c \u0111\u00f3 kh\u00f4ng b\u1ecb x\u00f3a v\u00e0 URL b\u1ecb l\u1eb7p. M\u00ecnh ph\u00e1t hi\u1ec7n ra khi \u0111\u00e3 c\u00f3 23 m\u1ee5c tr\u00f9ng, v\u00e0 s\u1eeda \u1edf commit `d754107`. T\u1eeb \u0111\u00f3 m\u1ed7i l\u1ea7n commit \u0111\u1ec1u \u0111\u1ebfm l\u1ea1i `<loc>`. Hi\u1ec7n sitemap c\u00f3 1.237 URL.\n\n## Ch\u1ec9 add \u0111\u00fang nh\u1eefng file \u0111\u00e3 ki\u1ec3m tra\n\nDanh s\u00e1ch file \u0111\u01b0\u1ee3c commit g\u1ed3m ba ph\u1ea7n: file m\u1edbi c\u1ee7a \u0111\u1ee3t n\u00e0y, file m\u00ecnh s\u1eeda tay, v\u00e0 nh\u1eefng file c\u00f3 c\u00f9ng slug m\u00e0 sync v\u1eeba ghi l\u1ea1i (l\u1ea5y t\u1eeb `git diff --name-only`):\n\n```python\nsynced=[m for m in mod if os.path.basename(m) in slugs]\nfiles=sorted(set(new+edited+synced))\nsubprocess.run(['git','add']+files+['sitemap.xml','llms.txt','llms-full.txt'],check=True)\n```\n\nKh\u00f4ng d\u00f9ng `git add -A` hay `git add .`. Nh\u1edd v\u1eady c\u00e1c file c\u1ee7a \u0111\u1ee3t d\u1ecbch kh\u00e1c v\u1eabn n\u1eb1m y\u00ean \u1edf tr\u1ea1ng th\u00e1i untracked, v\u00e0 l\u1ea7n ch\u1ea1y sau ch\u00fang l\u1ea1i b\u1ecb lo\u1ea1i kh\u1ecfi hreflang cho \u0111\u1ebfn khi \u0111\u1ee3t c\u1ee7a ch\u00fang xong.\n\n## T\u00f3m l\u1ea1i\n\n- Coi git l\u00e0 ngu\u1ed3n s\u1ef1 th\u1eadt cho c\u00e2u h\u1ecfi \"trang n\u00e0o \u0111\u00e3 xong\", c\u00f2n \u1ed5 \u0111\u0129a ch\u1ec9 l\u00e0 n\u01a1i \u0111ang l\u00e0m vi\u1ec7c.\n- Mu\u1ed1n \u0111\u1ed5i h\u00e0nh vi c\u1ee7a m\u1ed9t script nh\u1ecf cho m\u1ed9t tr\u01b0\u1eddng h\u1ee3p ri\u00eang th\u00ec c\u00f3 th\u1ec3 t\u1ea1o b\u1ea3n sao \u0111\u00e3 v\u00e1 l\u00fac ch\u1ea1y, script g\u1ed1c gi\u1eef nguy\u00ean.\n- V\u00e1 b\u1eb1ng `replace` c\u00f3 th\u1ec3 \u00e2m th\u1ea7m kh\u00f4ng kh\u1edbp, n\u00ean ph\u1ea3i c\u00f3 m\u1ed9t b\u01b0\u1edbc ki\u1ec3m tra \u0111\u1ed9c l\u1eadp \u1edf cu\u1ed1i (link ph\u1ea3i c\u00f3 trong git, JSON-LD parse \u0111\u01b0\u1ee3c, sitemap kh\u00f4ng tr\u00f9ng).\n- `git add` theo danh s\u00e1ch file c\u1ee5 th\u1ec3 \u0111\u1ec3 nhi\u1ec1u \u0111\u1ee3t d\u1ecbch c\u00f9ng t\u1ed3n t\u1ea1i trong working tree m\u00e0 kh\u00f4ng \u1ea3nh h\u01b0\u1edfng nhau.\n\nhttps:\/\/minulo.app\/vi\/?ref=viblo-vi-integ-1025j","published_at":"2026-10-25T07:47:18.000000Z","scheduled_publish_at":null,"is_published":true,"is_shared":false,"updated_at":"2026-10-25T12:10:04.000000Z","edited_at":"2026-10-25T07:45:58.000000Z","translation_source":null,"trend_at":null,"promoted_at":null,"reading_time":6,"points":0,"views_count":8,"clips_count":0,"comments_count":0,"rated_value":null,"promoted":false,"trending":false,"is_draft":false,"is_public":true,"locale_code":"vi","is_video":false,"thumbnail_url":"https:\/\/images.viblo.asia\/1b7c0520-805d-46da-a5d5-bf1a6850bb5a.png","user":{"data":{"id":226329,"url":"https:\/\/viblo.asia\/u\/barcaak1011","avatar":null,"name":"ayumu kitabayashi","username":"barcaak1011","followers_count":0,"reputation":0,"posts_count":4,"banned_at":null,"level_partner":null,"following":false}},"tags":{"data":[{"slug":"git","name":"Git"},{"slug":"github-pages","name":"Github Pages"},{"slug":"python","name":"Python"},{"slug":"seo","name":"SEO"},{"slug":"hreflang","name":"hreflang"}]},"commentators":{"data":[]}}],"meta":{"pagination":{"total":52126,"count":20,"per_page":20,"current_page":1,"total_pages":2607,"links":{"next":"http:\/\/viblo.asia\/posts?page=2"}}}}