[{"data":1,"prerenderedAt":2324},["ShallowReactive",2],{"navigation_docs":3,"-tu-hoc-database-postgresql-truy-van-nang-cao":420,"-tu-hoc-database-postgresql-truy-van-nang-cao-surround":2319},[4,153],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":26},"Phỏng vấn .NET","i-lucide-briefcase","\u002Fphong-van","1.phong-van",[10,27,66,111,128],{"title":11,"icon":12,"path":13,"stem":14,"children":15,"page":26},"Tổng quan","i-lucide-compass","\u002Fphong-van\u002Ftong-quan","1.phong-van\u002F1.tong-quan",[16,21],{"title":17,"path":18,"stem":19,"icon":20},"Thị trường HCM","\u002Fphong-van\u002Ftong-quan\u002Fthi-truong","1.phong-van\u002F1.tong-quan\u002F1.thi-truong","i-lucide-trending-up",{"title":22,"path":23,"stem":24,"icon":25},"Lộ trình 7 ngày","\u002Fphong-van\u002Ftong-quan\u002Flo-trinh","1.phong-van\u002F1.tong-quan\u002F2.lo-trinh","i-lucide-calendar-days",false,{"title":22,"icon":25,"path":28,"stem":29,"children":30,"page":26},"\u002Fphong-van\u002Flo-trinh","1.phong-van\u002F2.lo-trinh",[31,36,41,46,51,56,61],{"title":32,"path":33,"stem":34,"icon":35},"Ngày 1 — C# cơ bản","\u002Fphong-van\u002Flo-trinh\u002Fngay-1-csharp-co-ban","1.phong-van\u002F2.lo-trinh\u002F1.ngay-1-csharp-co-ban","i-lucide-1",{"title":37,"path":38,"stem":39,"icon":40},"Ngày 2 — OOP và SOLID","\u002Fphong-van\u002Flo-trinh\u002Fngay-2-oop-solid","1.phong-van\u002F2.lo-trinh\u002F2.ngay-2-oop-solid","i-lucide-2",{"title":42,"path":43,"stem":44,"icon":45},"Ngày 3 — C# nâng cao","\u002Fphong-van\u002Flo-trinh\u002Fngay-3-csharp-nang-cao","1.phong-van\u002F2.lo-trinh\u002F3.ngay-3-csharp-nang-cao","i-lucide-3",{"title":47,"path":48,"stem":49,"icon":50},"Ngày 4 — Database và SQL","\u002Fphong-van\u002Flo-trinh\u002Fngay-4-database-sql","1.phong-van\u002F2.lo-trinh\u002F4.ngay-4-database-sql","i-lucide-4",{"title":52,"path":53,"stem":54,"icon":55},"Ngày 5 — ASP.NET Core và EF Core","\u002Fphong-van\u002Flo-trinh\u002Fngay-5-aspnet-efcore","1.phong-van\u002F2.lo-trinh\u002F5.ngay-5-aspnet-efcore","i-lucide-5",{"title":57,"path":58,"stem":59,"icon":60},"Ngày 6 — DSA coding","\u002Fphong-van\u002Flo-trinh\u002Fngay-6-dsa","1.phong-van\u002F2.lo-trinh\u002F6.ngay-6-dsa","i-lucide-6",{"title":62,"path":63,"stem":64,"icon":65},"Ngày 7 — Mock và HR","\u002Fphong-van\u002Flo-trinh\u002Fngay-7-mock-interview","1.phong-van\u002F2.lo-trinh\u002F7.ngay-7-mock-interview","i-lucide-7",{"title":67,"icon":68,"path":69,"stem":70,"children":71,"page":26},"Ngân hàng câu hỏi","i-lucide-database","\u002Fphong-van\u002Fngan-hang-cau-hoi","1.phong-van\u002F3.ngan-hang-cau-hoi",[72,77,82,87,92,97,102,107],{"title":73,"path":74,"stem":75,"icon":76},"C# (60+ câu)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fcsharp","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F1.csharp","i-lucide-hash",{"title":78,"path":79,"stem":80,"icon":81},"OOP và SOLID (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Foop","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F2.oop","i-lucide-shapes",{"title":83,"path":84,"stem":85,"icon":86},"SQL (40+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fsql","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F3.sql","i-lucide-database-zap",{"title":88,"path":89,"stem":90,"icon":91},"ASP.NET và EF (50+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-ef","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F4.aspnet-ef","i-lucide-server",{"title":93,"path":94,"stem":95,"icon":96},"DSA và Coding (30+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdsa-coding","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F5.dsa-coding","i-lucide-binary",{"title":98,"path":99,"stem":100,"icon":101},"HR và Soft skill (25+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fhr-behavior","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F6.hr-behavior","i-lucide-users",{"title":103,"path":104,"stem":105,"icon":106},"Design Pattern (55+)","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Fdesign-pattern","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F7.design-pattern","i-lucide-puzzle",{"title":108,"path":109,"stem":110,"icon":91},"ASP.NET MVC và Web API","\u002Fphong-van\u002Fngan-hang-cau-hoi\u002Faspnet-mvc-webapi","1.phong-van\u002F3.ngan-hang-cau-hoi\u002F8.aspnet-mvc-webapi",{"title":112,"itle":113,"icon":114,"path":115,"stem":116,"children":117,"page":26},"Tai Lieu","Tài liệu và Cheat sheet","i-lucide-book-marked","\u002Fphong-van\u002Ftai-lieu","1.phong-van\u002F4.tai-lieu",[118,123],{"title":119,"path":120,"stem":121,"icon":122},"Cheat Sheet","\u002Fphong-van\u002Ftai-lieu\u002Fcheatsheet","1.phong-van\u002F4.tai-lieu\u002F1.cheatsheet","i-lucide-clipboard-list",{"title":124,"path":125,"stem":126,"icon":127},"Nguồn tham khảo","\u002Fphong-van\u002Ftai-lieu\u002Fnguon","1.phong-van\u002F4.tai-lieu\u002F2.nguon","i-lucide-link",{"title":129,"icon":130,"path":131,"stem":132,"children":133,"page":26},"Phỏng vấn English","i-lucide-globe","\u002Fphong-van\u002Fenglish-interview","1.phong-van\u002F5.english-interview",[134,138,143,148],{"title":135,"path":136,"stem":137,"icon":130},"Tổng quan English","\u002Fphong-van\u002Fenglish-interview\u002Ftong-quan","1.phong-van\u002F5.english-interview\u002F1.tong-quan",{"title":139,"path":140,"stem":141,"icon":142},"Vocabulary","\u002Fphong-van\u002Fenglish-interview\u002Fvocabulary","1.phong-van\u002F5.english-interview\u002F2.vocabulary","i-lucide-book-a",{"title":144,"path":145,"stem":146,"icon":147},"Technical Q và A (EN)","\u002Fphong-van\u002Fenglish-interview\u002Ftechnical-en","1.phong-van\u002F5.english-interview\u002F3.technical-en","i-lucide-code",{"title":149,"path":150,"stem":151,"icon":152},"Behavioral (EN)","\u002Fphong-van\u002Fenglish-interview\u002Fbehavioral-en","1.phong-van\u002F5.english-interview\u002F4.behavioral-en","i-lucide-message-square-text",{"title":154,"icon":155,"path":156,"stem":157,"children":158},"Tự học","i-lucide-graduation-cap","\u002Ftu-hoc","2.tu-hoc",[159,161,287,310,333,357,384],{"title":154,"path":156,"stem":160,"icon":155},"2.tu-hoc\u002Findex",{"title":162,"icon":68,"path":163,"stem":164,"children":165},"Database","\u002Ftu-hoc\u002Fdatabase","2.tu-hoc\u002F1.database\u002Findex",[166,167,197,222,243,248],{"title":162,"path":163,"stem":164,"icon":68},{"title":168,"icon":91,"path":169,"stem":170,"children":171,"page":26},"SQL Server","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server","2.tu-hoc\u002F1.database\u002F2.sql-server",[172,177,182,187,192],{"title":173,"path":174,"stem":175,"icon":176},"1. Giới thiệu và Cài đặt","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F1.gioi-thieu-cai-dat","i-lucide-play-circle",{"title":178,"path":179,"stem":180,"icon":181},"2. Cú pháp cơ bản","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F2.cu-phap-co-ban","i-lucide-code-2",{"title":183,"path":184,"stem":185,"icon":186},"3. Truy vấn nâng cao","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F3.truy-van-nang-cao","i-lucide-git-merge",{"title":188,"path":189,"stem":190,"icon":191},"4. Đặc thù và Performance","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F4.dac-thu-performance","i-lucide-gauge",{"title":193,"path":194,"stem":195,"icon":196},"5. Q và A phỏng vấn","\u002Ftu-hoc\u002Fdatabase\u002Fsql-server\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F2.sql-server\u002F5.cau-hoi-phong-van","i-lucide-message-circle-question",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":26},"PostgreSQL","i-simple-icons-postgresql","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql","2.tu-hoc\u002F1.database\u002F3.postgresql",[203,206,209,212,215,218],{"title":173,"path":204,"stem":205,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":207,"stem":208,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F2.cu-phap-co-ban",{"title":183,"path":210,"stem":211,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F3.truy-van-nang-cao",{"title":188,"path":213,"stem":214,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F4.dac-thu-performance",{"title":193,"path":216,"stem":217,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F5.cau-hoi-phong-van",{"title":219,"path":220,"stem":221,"icon":96},"6. Tích hợp C# và Postgres","\u002Ftu-hoc\u002Fdatabase\u002Fpostgresql\u002Ftich-hop-csharp","2.tu-hoc\u002F1.database\u002F3.postgresql\u002F6.tich-hop-csharp",{"title":223,"icon":224,"path":225,"stem":226,"children":227,"page":26},"MySQL","i-simple-icons-mysql","\u002Ftu-hoc\u002Fdatabase\u002Fmysql","2.tu-hoc\u002F1.database\u002F4.mysql",[228,231,234,237,240],{"title":173,"path":229,"stem":230,"icon":176},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F1.database\u002F4.mysql\u002F1.gioi-thieu-cai-dat",{"title":178,"path":232,"stem":233,"icon":181},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcu-phap-co-ban","2.tu-hoc\u002F1.database\u002F4.mysql\u002F2.cu-phap-co-ban",{"title":183,"path":235,"stem":236,"icon":186},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Ftruy-van-nang-cao","2.tu-hoc\u002F1.database\u002F4.mysql\u002F3.truy-van-nang-cao",{"title":188,"path":238,"stem":239,"icon":191},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fdac-thu-performance","2.tu-hoc\u002F1.database\u002F4.mysql\u002F4.dac-thu-performance",{"title":193,"path":241,"stem":242,"icon":196},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fcau-hoi-phong-van","2.tu-hoc\u002F1.database\u002F4.mysql\u002F5.cau-hoi-phong-van",{"title":244,"path":245,"stem":246,"icon":247},"So sánh 3 RDBMS","\u002Ftu-hoc\u002Fdatabase\u002Fso-sanh","2.tu-hoc\u002F1.database\u002F5.so-sanh","i-lucide-columns-3",{"title":249,"path":250,"stem":251,"children":252,"icon":254},"Supabase (BaaS)","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002Findex",[253,255,259,264,269,274,278,283],{"title":249,"path":250,"stem":251,"icon":254},"i-simple-icons-supabase",{"title":256,"path":257,"stem":258,"icon":68},"1. Database","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fdatabase","2.tu-hoc\u002F1.database\u002F6.supabase\u002F1.database",{"title":260,"path":261,"stem":262,"icon":263},"2. Authentication","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fauthentication","2.tu-hoc\u002F1.database\u002F6.supabase\u002F2.authentication","i-lucide-key",{"title":265,"path":266,"stem":267,"icon":268},"3. Storage & Realtime","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fstorage-realtime","2.tu-hoc\u002F1.database\u002F6.supabase\u002F3.storage-realtime","i-lucide-zap",{"title":270,"path":271,"stem":272,"icon":273},"4. Edge Functions & AI","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Ffunctions-ai","2.tu-hoc\u002F1.database\u002F6.supabase\u002F4.functions-ai","i-lucide-brain",{"title":275,"path":276,"stem":277,"icon":181},"5. API & SDKs","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fapi-sdk","2.tu-hoc\u002F1.database\u002F6.supabase\u002F5.api-sdk",{"title":279,"path":280,"stem":281,"icon":282},"6. Platform & Deploy","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Fplatform-deploy","2.tu-hoc\u002F1.database\u002F6.supabase\u002F6.platform-deploy","i-lucide-cloud",{"title":284,"path":285,"stem":286,"icon":196},"7. Interview & Q&A","\u002Ftu-hoc\u002Fdatabase\u002Fsupabase\u002Finterview","2.tu-hoc\u002F1.database\u002F6.supabase\u002F7.interview",{"title":288,"icon":289,"path":290,"stem":291,"children":292},"TypeScript","i-simple-icons-typescript","\u002Ftu-hoc\u002Ftypescript","2.tu-hoc\u002F2.typescript\u002Findex",[293,294,297,301,306],{"title":288,"path":290,"stem":291,"icon":289},{"title":173,"path":295,"stem":296,"icon":176},"\u002Ftu-hoc\u002Ftypescript\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F2.typescript\u002F1.gioi-thieu-cai-dat",{"title":298,"path":299,"stem":300,"icon":81},"2. Type System","\u002Ftu-hoc\u002Ftypescript\u002Ftype-system","2.tu-hoc\u002F2.typescript\u002F2.type-system",{"title":302,"path":303,"stem":304,"icon":305},"3. Advanced types","\u002Ftu-hoc\u002Ftypescript\u002Fadvanced-types","2.tu-hoc\u002F2.typescript\u002F3.advanced-types","i-lucide-braces",{"title":307,"path":308,"stem":309,"icon":196},"4. Q và A phỏng vấn","\u002Ftu-hoc\u002Ftypescript\u002Fcau-hoi-phong-van","2.tu-hoc\u002F2.typescript\u002F4.cau-hoi-phong-van",{"title":311,"icon":81,"path":312,"stem":313,"children":314},"OOP","\u002Ftu-hoc\u002Foop","2.tu-hoc\u002F3.oop\u002Findex",[315,316,321,326,330],{"title":311,"path":312,"stem":313,"icon":81},{"title":317,"path":318,"stem":319,"icon":320},"1. Bốn tính chất","\u002Ftu-hoc\u002Foop\u002F4-tinh-chat","2.tu-hoc\u002F3.oop\u002F1.4-tinh-chat","i-lucide-circle-dot",{"title":322,"path":323,"stem":324,"icon":325},"2. SOLID","\u002Ftu-hoc\u002Foop\u002Fsolid","2.tu-hoc\u002F3.oop\u002F2.solid","i-lucide-shield",{"title":327,"path":328,"stem":329,"icon":106},"3. Design Pattern","\u002Ftu-hoc\u002Foop\u002Fdesign-pattern","2.tu-hoc\u002F3.oop\u002F3.design-pattern",{"title":307,"path":331,"stem":332,"icon":196},"\u002Ftu-hoc\u002Foop\u002Fcau-hoi-phong-van","2.tu-hoc\u002F3.oop\u002F4.cau-hoi-phong-van",{"title":334,"icon":305,"path":335,"stem":336,"children":337},"Generic","\u002Ftu-hoc\u002Fgeneric","2.tu-hoc\u002F4.generic\u002Findex",[338,339,344,349,354],{"title":334,"path":335,"stem":336,"icon":305},{"title":340,"path":341,"stem":342,"icon":343},"1. Khái niệm và cú pháp","\u002Ftu-hoc\u002Fgeneric\u002Fkhai-niem","2.tu-hoc\u002F4.generic\u002F1.khai-niem","i-lucide-book",{"title":345,"path":346,"stem":347,"icon":348},"2. Constraint và Variance","\u002Ftu-hoc\u002Fgeneric\u002Fconstraint-variance","2.tu-hoc\u002F4.generic\u002F2.constraint-variance","i-lucide-filter",{"title":350,"path":351,"stem":352,"icon":353},"3. C# vs TS","\u002Ftu-hoc\u002Fgeneric\u002Fso-sanh","2.tu-hoc\u002F4.generic\u002F3.so-sanh","i-lucide-git-compare",{"title":307,"path":355,"stem":356,"icon":196},"\u002Ftu-hoc\u002Fgeneric\u002Fcau-hoi-phong-van","2.tu-hoc\u002F4.generic\u002F4.cau-hoi-phong-van",{"title":358,"icon":359,"path":360,"stem":361,"children":362},"Nuxt 4","i-simple-icons-nuxt","\u002Ftu-hoc\u002Fnuxt-4","2.tu-hoc\u002F5.nuxt-4\u002Findex",[363,364,367,372,376,379],{"title":358,"path":360,"stem":361,"icon":359},{"title":173,"path":365,"stem":366,"icon":176},"\u002Ftu-hoc\u002Fnuxt-4\u002Fgioi-thieu-cai-dat","2.tu-hoc\u002F5.nuxt-4\u002F1.gioi-thieu-cai-dat",{"title":368,"path":369,"stem":370,"icon":371},"2. Routing và Rendering","\u002Ftu-hoc\u002Fnuxt-4\u002Frouting-rendering","2.tu-hoc\u002F5.nuxt-4\u002F2.routing-rendering","i-lucide-route",{"title":373,"path":374,"stem":375,"icon":91},"3. Data và Server","\u002Ftu-hoc\u002Fnuxt-4\u002Fdata-server","2.tu-hoc\u002F5.nuxt-4\u002F3.data-server",{"title":307,"path":377,"stem":378,"icon":196},"\u002Ftu-hoc\u002Fnuxt-4\u002Fcau-hoi-phong-van","2.tu-hoc\u002F5.nuxt-4\u002F4.cau-hoi-phong-van",{"title":380,"path":381,"stem":382,"icon":383},"5. Practical Todo App","\u002Ftu-hoc\u002Fnuxt-4\u002Fpractical-todo-app","2.tu-hoc\u002F5.nuxt-4\u002F5.practical-todo-app","i-lucide-check-square",{"title":385,"path":386,"stem":387,"children":388,"icon":390},"Tailwind CSS","\u002Ftu-hoc\u002Ftailwindcss","2.tu-hoc\u002F6.tailwindcss\u002Findex",[389,391,396,401,406,411,416],{"title":385,"path":386,"stem":387,"icon":390},"i-simple-icons-tailwindcss",{"title":392,"path":393,"stem":394,"icon":395},"1. Layout & Spacing","\u002Ftu-hoc\u002Ftailwindcss\u002Flayout-spacing","2.tu-hoc\u002F6.tailwindcss\u002F1.layout-spacing","i-lucide-layout",{"title":397,"path":398,"stem":399,"icon":400},"2. Typography & Colors","\u002Ftu-hoc\u002Ftailwindcss\u002Ftypography-colors","2.tu-hoc\u002F6.tailwindcss\u002F2.typography-colors","i-lucide-type",{"title":402,"path":403,"stem":404,"icon":405},"3. Interactive & Effects","\u002Ftu-hoc\u002Ftailwindcss\u002Finteractive-effects","2.tu-hoc\u002F6.tailwindcss\u002F3.interactive-effects","i-lucide-sparkles",{"title":407,"path":408,"stem":409,"icon":410},"4. Responsive & Dark Mode","\u002Ftu-hoc\u002Ftailwindcss\u002Fresponsive-darkmode","2.tu-hoc\u002F6.tailwindcss\u002F4.responsive-darkmode","i-lucide-monitor-smartphone",{"title":412,"path":413,"stem":414,"icon":415},"5. Customization & Theme","\u002Ftu-hoc\u002Ftailwindcss\u002Fcustomization","2.tu-hoc\u002F6.tailwindcss\u002F5.customization","i-lucide-settings-2",{"title":417,"path":418,"stem":419,"icon":181},"6. Practical Projects","\u002Ftu-hoc\u002Ftailwindcss\u002Fpractical-projects","2.tu-hoc\u002F6.tailwindcss\u002F6.practical-projects",{"id":421,"title":422,"body":423,"description":2312,"extension":2313,"links":2314,"meta":2315,"navigation":2316,"path":210,"seo":2317,"stem":211,"__hash__":2318},"docs\u002F2.tu-hoc\u002F1.database\u002F3.postgresql\u002F3.truy-van-nang-cao.md","Truy vấn PostgreSQL nâng cao",{"type":424,"value":425,"toc":2272},"minimark",[426,431,453,458,512,516,580,598,602,606,641,645,700,704,768,772,783,843,847,942,963,1053,1057,1072,1076,1101,1108,1112,1170,1183,1187,1249,1253,1311,1315,1400,1404,1431,1435,1523,1546,1576,1580,1587,1607,1611,1615,1639,1649,1653,1761,1768,1771,1775,1797,1801,1841,1849,1874,1878,1885,1889,1942,1957,1961,1971,1975,1986,1989,2078,2082,2151,2214,2218,2238,2260,2268],[427,428,430],"h2",{"id":429},"_1-join-giống-chuẩn-ansi","1. JOIN — giống chuẩn ANSI",[432,433,434,435,439,440,439,443,439,446,439,449,452],"p",{},"Cú pháp y hệt SQL Server cho ",[436,437,438],"code",{},"INNER",", ",[436,441,442],{},"LEFT",[436,444,445],{},"RIGHT",[436,447,448],{},"FULL OUTER",[436,450,451],{},"CROSS",". Bẫy LEFT JOIN + WHERE cũng tương tự (đặt vào ON).",[454,455,457],"h3",{"id":456},"khác-biệt-nhỏ-postgres-specific","Khác biệt nhỏ Postgres-specific",[459,460,465],"pre",{"className":461,"code":462,"language":463,"meta":464,"style":464},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","-- USING — JOIN trên cột cùng tên\nSELECT u.id, u.name, o.total\nFROM users u JOIN orders o USING (id);    -- tự match user.id = orders.id\n                                          -- và chỉ trả 1 cột id\n\n-- NATURAL JOIN — tự JOIN trên tất cả cột cùng tên (tránh dùng — nguy hiểm)\nSELECT * FROM a NATURAL JOIN b;\n","sql","",[436,466,467,475,481,487,493,500,506],{"__ignoreMap":464},[468,469,472],"span",{"class":470,"line":471},"line",1,[468,473,474],{},"-- USING — JOIN trên cột cùng tên\n",[468,476,478],{"class":470,"line":477},2,[468,479,480],{},"SELECT u.id, u.name, o.total\n",[468,482,484],{"class":470,"line":483},3,[468,485,486],{},"FROM users u JOIN orders o USING (id);    -- tự match user.id = orders.id\n",[468,488,490],{"class":470,"line":489},4,[468,491,492],{},"                                          -- và chỉ trả 1 cột id\n",[468,494,496],{"class":470,"line":495},5,[468,497,499],{"emptyLinePlaceholder":498},true,"\n",[468,501,503],{"class":470,"line":502},6,[468,504,505],{},"-- NATURAL JOIN — tự JOIN trên tất cả cột cùng tên (tránh dùng — nguy hiểm)\n",[468,507,509],{"class":470,"line":508},7,[468,510,511],{},"SELECT * FROM a NATURAL JOIN b;\n",[427,513,515],{"id":514},"_2-lateral-join-đặc-thù-mạnh","2. LATERAL JOIN — đặc thù mạnh",[459,517,519],{"className":461,"code":518,"language":463,"meta":464,"style":464},"-- LATERAL cho phép subquery bên phải REFERENCE bảng bên trái\n-- Ví dụ: top 3 đơn mới nhất của mỗi user\nSELECT u.id, u.name, o.*\nFROM users u\nLEFT JOIN LATERAL (\n    SELECT *\n    FROM orders\n    WHERE user_id = u.id\n    ORDER BY created_at DESC\n    LIMIT 3\n) o ON true;\n",[436,520,521,526,531,536,541,546,551,556,562,568,574],{"__ignoreMap":464},[468,522,523],{"class":470,"line":471},[468,524,525],{},"-- LATERAL cho phép subquery bên phải REFERENCE bảng bên trái\n",[468,527,528],{"class":470,"line":477},[468,529,530],{},"-- Ví dụ: top 3 đơn mới nhất của mỗi user\n",[468,532,533],{"class":470,"line":483},[468,534,535],{},"SELECT u.id, u.name, o.*\n",[468,537,538],{"class":470,"line":489},[468,539,540],{},"FROM users u\n",[468,542,543],{"class":470,"line":495},[468,544,545],{},"LEFT JOIN LATERAL (\n",[468,547,548],{"class":470,"line":502},[468,549,550],{},"    SELECT *\n",[468,552,553],{"class":470,"line":508},[468,554,555],{},"    FROM orders\n",[468,557,559],{"class":470,"line":558},8,[468,560,561],{},"    WHERE user_id = u.id\n",[468,563,565],{"class":470,"line":564},9,[468,566,567],{},"    ORDER BY created_at DESC\n",[468,569,571],{"class":470,"line":570},10,[468,572,573],{},"    LIMIT 3\n",[468,575,577],{"class":470,"line":576},11,[468,578,579],{},") o ON true;\n",[581,582,585,586,593,594,597],"callout",{"color":583,"icon":584},"warning","i-lucide-star","⭐ ",[587,588,589,592],"strong",{},[436,590,591],{},"LATERAL"," là sức mạnh độc đáo của Postgres."," Tương đương ",[436,595,596],{},"CROSS APPLY"," của SQL Server. Cho phép giải các bài \"top N per group\" + parameterized subquery rất gọn.",[427,599,601],{"id":600},"_3-cte-bao-gồm-recursive","3. CTE — bao gồm Recursive",[454,603,605],{"id":604},"cú-pháp-như-sql-server","Cú pháp như SQL Server",[459,607,609],{"className":461,"code":608,"language":463,"meta":464,"style":464},"WITH high_value AS (\n    SELECT * FROM orders WHERE total > 10000000\n)\nSELECT u.name, COUNT(*)\nFROM high_value h JOIN users u ON u.id = h.user_id\nGROUP BY u.name;\n",[436,610,611,616,621,626,631,636],{"__ignoreMap":464},[468,612,613],{"class":470,"line":471},[468,614,615],{},"WITH high_value AS (\n",[468,617,618],{"class":470,"line":477},[468,619,620],{},"    SELECT * FROM orders WHERE total > 10000000\n",[468,622,623],{"class":470,"line":483},[468,624,625],{},")\n",[468,627,628],{"class":470,"line":489},[468,629,630],{},"SELECT u.name, COUNT(*)\n",[468,632,633],{"class":470,"line":495},[468,634,635],{},"FROM high_value h JOIN users u ON u.id = h.user_id\n",[468,637,638],{"class":470,"line":502},[468,639,640],{},"GROUP BY u.name;\n",[454,642,644],{"id":643},"postgres-12-inline-vs-materialized","Postgres 12+ — Inline vs Materialized",[459,646,648],{"className":461,"code":647,"language":463,"meta":464,"style":464},"-- MATERIALIZED — bắt CTE chạy 1 lần, cache (cũ default)\nWITH cte AS MATERIALIZED (\n    SELECT * FROM big_table WHERE x > 100\n)\nSELECT ...;\n\n-- NOT MATERIALIZED — inline (default 12+, planner tối ưu tốt hơn)\nWITH cte AS NOT MATERIALIZED (\n    SELECT * FROM big_table WHERE x > 100\n)\nSELECT ...;\n",[436,649,650,655,660,665,669,674,678,683,688,692,696],{"__ignoreMap":464},[468,651,652],{"class":470,"line":471},[468,653,654],{},"-- MATERIALIZED — bắt CTE chạy 1 lần, cache (cũ default)\n",[468,656,657],{"class":470,"line":477},[468,658,659],{},"WITH cte AS MATERIALIZED (\n",[468,661,662],{"class":470,"line":483},[468,663,664],{},"    SELECT * FROM big_table WHERE x > 100\n",[468,666,667],{"class":470,"line":489},[468,668,625],{},[468,670,671],{"class":470,"line":495},[468,672,673],{},"SELECT ...;\n",[468,675,676],{"class":470,"line":502},[468,677,499],{"emptyLinePlaceholder":498},[468,679,680],{"class":470,"line":508},[468,681,682],{},"-- NOT MATERIALIZED — inline (default 12+, planner tối ưu tốt hơn)\n",[468,684,685],{"class":470,"line":558},[468,686,687],{},"WITH cte AS NOT MATERIALIZED (\n",[468,689,690],{"class":470,"line":564},[468,691,664],{},[468,693,694],{"class":470,"line":570},[468,695,625],{},[468,697,698],{"class":470,"line":576},[468,699,673],{},[454,701,703],{"id":702},"recursive-cte","Recursive CTE",[459,705,707],{"className":461,"code":706,"language":463,"meta":464,"style":464},"-- Build cây tổ chức từ root\nWITH RECURSIVE org AS (\n    SELECT id, name, manager_id, 0 AS lvl, name::TEXT AS path\n    FROM employees WHERE manager_id IS NULL\n    \n    UNION ALL\n    \n    SELECT e.id, e.name, e.manager_id, o.lvl + 1, o.path || ' > ' || e.name\n    FROM employees e\n    JOIN org o ON o.id = e.manager_id\n)\nSELECT * FROM org ORDER BY path;\n",[436,708,709,714,719,724,729,734,739,743,748,753,758,762],{"__ignoreMap":464},[468,710,711],{"class":470,"line":471},[468,712,713],{},"-- Build cây tổ chức từ root\n",[468,715,716],{"class":470,"line":477},[468,717,718],{},"WITH RECURSIVE org AS (\n",[468,720,721],{"class":470,"line":483},[468,722,723],{},"    SELECT id, name, manager_id, 0 AS lvl, name::TEXT AS path\n",[468,725,726],{"class":470,"line":489},[468,727,728],{},"    FROM employees WHERE manager_id IS NULL\n",[468,730,731],{"class":470,"line":495},[468,732,733],{},"    \n",[468,735,736],{"class":470,"line":502},[468,737,738],{},"    UNION ALL\n",[468,740,741],{"class":470,"line":508},[468,742,733],{},[468,744,745],{"class":470,"line":558},[468,746,747],{},"    SELECT e.id, e.name, e.manager_id, o.lvl + 1, o.path || ' > ' || e.name\n",[468,749,750],{"class":470,"line":564},[468,751,752],{},"    FROM employees e\n",[468,754,755],{"class":470,"line":570},[468,756,757],{},"    JOIN org o ON o.id = e.manager_id\n",[468,759,760],{"class":470,"line":576},[468,761,625],{},[468,763,765],{"class":470,"line":764},12,[468,766,767],{},"SELECT * FROM org ORDER BY path;\n",[427,769,771],{"id":770},"_4-window-function","4. Window function",[432,773,774,775,778,779,782],{},"Cú pháp giống chuẩn (như SQL Server): ",[436,776,777],{},"OVER (PARTITION BY ... ORDER BY ...)",". Postgres hỗ trợ ",[587,780,781],{},"nhiều function nhất"," — full list:",[784,785,786,809,827],"ul",{},[787,788,789,790,439,793,439,796,439,799,439,802,439,805,808],"li",{},"Ranking: ",[436,791,792],{},"ROW_NUMBER",[436,794,795],{},"RANK",[436,797,798],{},"DENSE_RANK",[436,800,801],{},"PERCENT_RANK",[436,803,804],{},"CUME_DIST",[436,806,807],{},"NTILE",".",[787,810,811,812,439,815,439,818,439,821,439,824,808],{},"Offset: ",[436,813,814],{},"LAG",[436,816,817],{},"LEAD",[436,819,820],{},"FIRST_VALUE",[436,822,823],{},"LAST_VALUE",[436,825,826],{},"NTH_VALUE",[787,828,829,830,439,833,439,836,839,840,808],{},"Aggregate over window: ",[436,831,832],{},"SUM",[436,834,835],{},"AVG",[436,837,838],{},"COUNT",", ... với ",[436,841,842],{},"OVER",[454,844,846],{"id":845},"postgres-19-ignore-nulls","Postgres 19 — IGNORE NULLS",[459,848,850],{"className":461,"code":849,"language":463,"meta":464,"style":464},"-- IGNORE NULLS — bỏ qua giá trị NULL trong window frame\n-- Áp dụng cho: lead(), lag(), first_value(), last_value(), nth_value()\nSELECT sensor_id, ts, reading,\n    last_value(reading) IGNORE NULLS OVER (\n        PARTITION BY sensor_id ORDER BY ts\n    ) AS last_known_reading\nFROM sensor_data;\n\n-- RESPECT NULLS là default — trả NULL nếu gặp NULL\n-- So sánh: IGNORE NULLS vs RESPECT NULLS\nSELECT sensor_id, ts, reading,\n    last_value(reading) RESPECT NULLS OVER (\n        PARTITION BY sensor_id ORDER BY ts\n    ) AS resp_nulls,\n    last_value(reading) IGNORE NULLS OVER (\n        PARTITION BY sensor_id ORDER BY ts\n    ) AS ignore_nulls\nFROM sensor_data;\n",[436,851,852,857,862,867,872,877,882,887,891,896,901,905,910,915,921,926,931,937],{"__ignoreMap":464},[468,853,854],{"class":470,"line":471},[468,855,856],{},"-- IGNORE NULLS — bỏ qua giá trị NULL trong window frame\n",[468,858,859],{"class":470,"line":477},[468,860,861],{},"-- Áp dụng cho: lead(), lag(), first_value(), last_value(), nth_value()\n",[468,863,864],{"class":470,"line":483},[468,865,866],{},"SELECT sensor_id, ts, reading,\n",[468,868,869],{"class":470,"line":489},[468,870,871],{},"    last_value(reading) IGNORE NULLS OVER (\n",[468,873,874],{"class":470,"line":495},[468,875,876],{},"        PARTITION BY sensor_id ORDER BY ts\n",[468,878,879],{"class":470,"line":502},[468,880,881],{},"    ) AS last_known_reading\n",[468,883,884],{"class":470,"line":508},[468,885,886],{},"FROM sensor_data;\n",[468,888,889],{"class":470,"line":558},[468,890,499],{"emptyLinePlaceholder":498},[468,892,893],{"class":470,"line":564},[468,894,895],{},"-- RESPECT NULLS là default — trả NULL nếu gặp NULL\n",[468,897,898],{"class":470,"line":570},[468,899,900],{},"-- So sánh: IGNORE NULLS vs RESPECT NULLS\n",[468,902,903],{"class":470,"line":576},[468,904,866],{},[468,906,907],{"class":470,"line":764},[468,908,909],{},"    last_value(reading) RESPECT NULLS OVER (\n",[468,911,913],{"class":470,"line":912},13,[468,914,876],{},[468,916,918],{"class":470,"line":917},14,[468,919,920],{},"    ) AS resp_nulls,\n",[468,922,924],{"class":470,"line":923},15,[468,925,871],{},[468,927,929],{"class":470,"line":928},16,[468,930,876],{},[468,932,934],{"class":470,"line":933},17,[468,935,936],{},"    ) AS ignore_nulls\n",[468,938,940],{"class":470,"line":939},18,[468,941,886],{},[581,943,585,944,947,948,439,950,439,952,439,954,439,956,958,959,962],{"color":583,"icon":584},[587,945,946],{},"PG 19 IGNORE NULLS."," ",[436,949,814],{},[436,951,817],{},[436,953,820],{},[436,955,823],{},[436,957,826],{}," đều hỗ trợ. Cực kỳ hữu ích cho dữ liệu sensor\u002Ftime-series có lỗ hổng NULL. SQL Server hỗ trợ từ 2025 (Azure SQL), Oracle có ",[436,960,961],{},"IGNORE NULLS"," từ lâu.",[459,964,966],{"className":461,"code":965,"language":463,"meta":464,"style":464},"-- Top N per group\nSELECT id, user_id, total\nFROM (\n    SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY total DESC) rn\n    FROM orders\n) t WHERE rn \u003C= 3;\n\n-- Running total\nSELECT order_date, total,\n    SUM(total) OVER (ORDER BY order_date) AS running_total,\n    AVG(total) OVER (ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS ma7\nFROM orders;\n\n-- Compare with previous row\nSELECT order_date, total,\n    LAG(total) OVER (ORDER BY order_date) AS prev_total,\n    total - LAG(total) OVER (ORDER BY order_date) AS delta\nFROM orders;\n",[436,967,968,973,978,983,988,992,997,1001,1006,1011,1016,1021,1026,1030,1035,1039,1044,1049],{"__ignoreMap":464},[468,969,970],{"class":470,"line":471},[468,971,972],{},"-- Top N per group\n",[468,974,975],{"class":470,"line":477},[468,976,977],{},"SELECT id, user_id, total\n",[468,979,980],{"class":470,"line":483},[468,981,982],{},"FROM (\n",[468,984,985],{"class":470,"line":489},[468,986,987],{},"    SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY total DESC) rn\n",[468,989,990],{"class":470,"line":495},[468,991,555],{},[468,993,994],{"class":470,"line":502},[468,995,996],{},") t WHERE rn \u003C= 3;\n",[468,998,999],{"class":470,"line":508},[468,1000,499],{"emptyLinePlaceholder":498},[468,1002,1003],{"class":470,"line":558},[468,1004,1005],{},"-- Running total\n",[468,1007,1008],{"class":470,"line":564},[468,1009,1010],{},"SELECT order_date, total,\n",[468,1012,1013],{"class":470,"line":570},[468,1014,1015],{},"    SUM(total) OVER (ORDER BY order_date) AS running_total,\n",[468,1017,1018],{"class":470,"line":576},[468,1019,1020],{},"    AVG(total) OVER (ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS ma7\n",[468,1022,1023],{"class":470,"line":764},[468,1024,1025],{},"FROM orders;\n",[468,1027,1028],{"class":470,"line":912},[468,1029,499],{"emptyLinePlaceholder":498},[468,1031,1032],{"class":470,"line":917},[468,1033,1034],{},"-- Compare with previous row\n",[468,1036,1037],{"class":470,"line":923},[468,1038,1010],{},[468,1040,1041],{"class":470,"line":928},[468,1042,1043],{},"    LAG(total) OVER (ORDER BY order_date) AS prev_total,\n",[468,1045,1046],{"class":470,"line":933},[468,1047,1048],{},"    total - LAG(total) OVER (ORDER BY order_date) AS delta\n",[468,1050,1051],{"class":470,"line":939},[468,1052,1025],{},[427,1054,1056],{"id":1055},"_5-set-operations","5. Set operations",[432,1058,1059,1060,439,1063,439,1066,439,1069,808],{},"Cú pháp giống SQL Server: ",[436,1061,1062],{},"UNION",[436,1064,1065],{},"UNION ALL",[436,1067,1068],{},"INTERSECT",[436,1070,1071],{},"EXCEPT",[427,1073,1075],{"id":1074},"_6-distinct-on-đặc-thù-postgres","6. DISTINCT ON — đặc thù Postgres",[459,1077,1079],{"className":461,"code":1078,"language":463,"meta":464,"style":464},"-- Đơn hàng mới nhất của mỗi user — viết ngắn hơn ROW_NUMBER\nSELECT DISTINCT ON (user_id) *\nFROM orders\nORDER BY user_id, created_at DESC;\n",[436,1080,1081,1086,1091,1096],{"__ignoreMap":464},[468,1082,1083],{"class":470,"line":471},[468,1084,1085],{},"-- Đơn hàng mới nhất của mỗi user — viết ngắn hơn ROW_NUMBER\n",[468,1087,1088],{"class":470,"line":477},[468,1089,1090],{},"SELECT DISTINCT ON (user_id) *\n",[468,1092,1093],{"class":470,"line":483},[468,1094,1095],{},"FROM orders\n",[468,1097,1098],{"class":470,"line":489},[468,1099,1100],{},"ORDER BY user_id, created_at DESC;\n",[581,1102,585,1104,1107],{"color":1103,"icon":584},"primary",[436,1105,1106],{},"DISTINCT ON"," chỉ Postgres có. Thường nhanh hơn ROW_NUMBER + WHERE rn=1.",[427,1109,1111],{"id":1110},"_7-aggregate-nâng-cao","7. Aggregate nâng cao",[459,1113,1115],{"className":461,"code":1114,"language":463,"meta":464,"style":464},"-- GROUPING SETS, ROLLUP, CUBE — giống SQL Server\nSELECT city, status, COUNT(*)\nFROM orders o JOIN users u ON u.id = o.user_id\nGROUP BY GROUPING SETS ((city, status), (city), ());\n\n-- FILTER — aggregate có điều kiện\nSELECT\n    COUNT(*) AS total,\n    COUNT(*) FILTER (WHERE status = 'paid') AS paid_count,\n    SUM(total) FILTER (WHERE status = 'paid') AS paid_revenue\nFROM orders;\n",[436,1116,1117,1122,1127,1132,1137,1141,1146,1151,1156,1161,1166],{"__ignoreMap":464},[468,1118,1119],{"class":470,"line":471},[468,1120,1121],{},"-- GROUPING SETS, ROLLUP, CUBE — giống SQL Server\n",[468,1123,1124],{"class":470,"line":477},[468,1125,1126],{},"SELECT city, status, COUNT(*)\n",[468,1128,1129],{"class":470,"line":483},[468,1130,1131],{},"FROM orders o JOIN users u ON u.id = o.user_id\n",[468,1133,1134],{"class":470,"line":489},[468,1135,1136],{},"GROUP BY GROUPING SETS ((city, status), (city), ());\n",[468,1138,1139],{"class":470,"line":495},[468,1140,499],{"emptyLinePlaceholder":498},[468,1142,1143],{"class":470,"line":502},[468,1144,1145],{},"-- FILTER — aggregate có điều kiện\n",[468,1147,1148],{"class":470,"line":508},[468,1149,1150],{},"SELECT\n",[468,1152,1153],{"class":470,"line":558},[468,1154,1155],{},"    COUNT(*) AS total,\n",[468,1157,1158],{"class":470,"line":564},[468,1159,1160],{},"    COUNT(*) FILTER (WHERE status = 'paid') AS paid_count,\n",[468,1162,1163],{"class":470,"line":570},[468,1164,1165],{},"    SUM(total) FILTER (WHERE status = 'paid') AS paid_revenue\n",[468,1167,1168],{"class":470,"line":576},[468,1169,1025],{},[581,1171,585,1172,1178,1179,1182],{"color":583,"icon":584},[587,1173,1174,1177],{},[436,1175,1176],{},"FILTER (WHERE ...)"," đặc thù Postgres"," — gọn hơn ",[436,1180,1181],{},"SUM(CASE WHEN ... THEN ... END)",". SQL Server không có.",[427,1184,1186],{"id":1185},"_8-json-query-trong-where","8. JSON query trong WHERE",[459,1188,1190],{"className":461,"code":1189,"language":463,"meta":464,"style":464},"-- Containment, fastest với GIN index\nSELECT * FROM events WHERE payload @> '{\"type\": \"click\"}';\n\n-- Path access\nSELECT * FROM events WHERE payload->>'type' = 'click';\n\n-- Array contains\nSELECT * FROM posts WHERE tags @> ARRAY['vue'];\n\n-- JSONB path query\nSELECT * FROM events\nWHERE payload @? '$.tags[*] ? (@ == \"promo\")';\n",[436,1191,1192,1197,1202,1206,1211,1216,1220,1225,1230,1234,1239,1244],{"__ignoreMap":464},[468,1193,1194],{"class":470,"line":471},[468,1195,1196],{},"-- Containment, fastest với GIN index\n",[468,1198,1199],{"class":470,"line":477},[468,1200,1201],{},"SELECT * FROM events WHERE payload @> '{\"type\": \"click\"}';\n",[468,1203,1204],{"class":470,"line":483},[468,1205,499],{"emptyLinePlaceholder":498},[468,1207,1208],{"class":470,"line":489},[468,1209,1210],{},"-- Path access\n",[468,1212,1213],{"class":470,"line":495},[468,1214,1215],{},"SELECT * FROM events WHERE payload->>'type' = 'click';\n",[468,1217,1218],{"class":470,"line":502},[468,1219,499],{"emptyLinePlaceholder":498},[468,1221,1222],{"class":470,"line":508},[468,1223,1224],{},"-- Array contains\n",[468,1226,1227],{"class":470,"line":558},[468,1228,1229],{},"SELECT * FROM posts WHERE tags @> ARRAY['vue'];\n",[468,1231,1232],{"class":470,"line":564},[468,1233,499],{"emptyLinePlaceholder":498},[468,1235,1236],{"class":470,"line":570},[468,1237,1238],{},"-- JSONB path query\n",[468,1240,1241],{"class":470,"line":576},[468,1242,1243],{},"SELECT * FROM events\n",[468,1245,1246],{"class":470,"line":764},[468,1247,1248],{},"WHERE payload @? '$.tags[*] ? (@ == \"promo\")';\n",[427,1250,1252],{"id":1251},"_9-full-text-search","9. Full-text search",[459,1254,1256],{"className":461,"code":1255,"language":463,"meta":464,"style":464},"-- Add tsvector column\nALTER TABLE articles\n    ADD COLUMN search_vector tsvector\n    GENERATED ALWAYS AS (to_tsvector('english', title || ' ' || content)) STORED;\n\n-- GIN index\nCREATE INDEX idx_articles_search ON articles USING GIN(search_vector);\n\n-- Query\nSELECT * FROM articles\nWHERE search_vector @@ to_tsquery('english', 'postgres & 18');\n",[436,1257,1258,1263,1268,1273,1278,1282,1287,1292,1296,1301,1306],{"__ignoreMap":464},[468,1259,1260],{"class":470,"line":471},[468,1261,1262],{},"-- Add tsvector column\n",[468,1264,1265],{"class":470,"line":477},[468,1266,1267],{},"ALTER TABLE articles\n",[468,1269,1270],{"class":470,"line":483},[468,1271,1272],{},"    ADD COLUMN search_vector tsvector\n",[468,1274,1275],{"class":470,"line":489},[468,1276,1277],{},"    GENERATED ALWAYS AS (to_tsvector('english', title || ' ' || content)) STORED;\n",[468,1279,1280],{"class":470,"line":495},[468,1281,499],{"emptyLinePlaceholder":498},[468,1283,1284],{"class":470,"line":502},[468,1285,1286],{},"-- GIN index\n",[468,1288,1289],{"class":470,"line":508},[468,1290,1291],{},"CREATE INDEX idx_articles_search ON articles USING GIN(search_vector);\n",[468,1293,1294],{"class":470,"line":558},[468,1295,499],{"emptyLinePlaceholder":498},[468,1297,1298],{"class":470,"line":564},[468,1299,1300],{},"-- Query\n",[468,1302,1303],{"class":470,"line":570},[468,1304,1305],{},"SELECT * FROM articles\n",[468,1307,1308],{"class":470,"line":576},[468,1309,1310],{},"WHERE search_vector @@ to_tsquery('english', 'postgres & 18');\n",[427,1312,1314],{"id":1313},"_10-transaction-mvcc","10. Transaction & MVCC",[459,1316,1318],{"className":461,"code":1317,"language":463,"meta":464,"style":464},"BEGIN;\nUPDATE accounts SET balance = balance - 1000 WHERE id = 1;\nUPDATE accounts SET balance = balance + 1000 WHERE id = 2;\nCOMMIT;\n\n-- ROLLBACK nếu lỗi\nBEGIN;\n... \nROLLBACK;\n\n-- Savepoint\nBEGIN;\nINSERT ...;\nSAVEPOINT sp1;\nUPDATE ...;\nROLLBACK TO sp1;     -- chỉ rollback từ sp1\nCOMMIT;\n",[436,1319,1320,1325,1330,1335,1340,1344,1349,1353,1358,1363,1367,1372,1376,1381,1386,1391,1396],{"__ignoreMap":464},[468,1321,1322],{"class":470,"line":471},[468,1323,1324],{},"BEGIN;\n",[468,1326,1327],{"class":470,"line":477},[468,1328,1329],{},"UPDATE accounts SET balance = balance - 1000 WHERE id = 1;\n",[468,1331,1332],{"class":470,"line":483},[468,1333,1334],{},"UPDATE accounts SET balance = balance + 1000 WHERE id = 2;\n",[468,1336,1337],{"class":470,"line":489},[468,1338,1339],{},"COMMIT;\n",[468,1341,1342],{"class":470,"line":495},[468,1343,499],{"emptyLinePlaceholder":498},[468,1345,1346],{"class":470,"line":502},[468,1347,1348],{},"-- ROLLBACK nếu lỗi\n",[468,1350,1351],{"class":470,"line":508},[468,1352,1324],{},[468,1354,1355],{"class":470,"line":558},[468,1356,1357],{},"... \n",[468,1359,1360],{"class":470,"line":564},[468,1361,1362],{},"ROLLBACK;\n",[468,1364,1365],{"class":470,"line":570},[468,1366,499],{"emptyLinePlaceholder":498},[468,1368,1369],{"class":470,"line":576},[468,1370,1371],{},"-- Savepoint\n",[468,1373,1374],{"class":470,"line":764},[468,1375,1324],{},[468,1377,1378],{"class":470,"line":912},[468,1379,1380],{},"INSERT ...;\n",[468,1382,1383],{"class":470,"line":917},[468,1384,1385],{},"SAVEPOINT sp1;\n",[468,1387,1388],{"class":470,"line":923},[468,1389,1390],{},"UPDATE ...;\n",[468,1392,1393],{"class":470,"line":928},[468,1394,1395],{},"ROLLBACK TO sp1;     -- chỉ rollback từ sp1\n",[468,1397,1398],{"class":470,"line":933},[468,1399,1339],{},[454,1401,1403],{"id":1402},"mvcc-cốt-lõi-postgres","MVCC — cốt lõi Postgres",[581,1405,1406,1415],{"color":583,"icon":584},[432,1407,585,1408,947,1411],{},[587,1409,1410],{},"Câu PV cốt lõi:",[1412,1413,1414],"em",{},"\"Postgres dùng MVCC, MVCC là gì?\"",[1416,1417,1418,1424],"blockquote",{},[432,1419,1420,1421],{},"\"Multi-Version Concurrency Control. Mỗi UPDATE\u002FDELETE không xoá row cũ ngay mà tạo version mới + đánh dấu version cũ là dead. Mỗi transaction thấy snapshot data tại thời điểm bắt đầu. ",[587,1422,1423],{},"Đọc không block ghi, ghi không block đọc.",[432,1425,1426,1427,1430],{},"Trade-off: row chết tích lũy → cần ",[436,1428,1429],{},"VACUUM"," (auto-vacuum chạy nền) để reclaim space.\"",[454,1432,1434],{"id":1433},"isolation-level","Isolation level",[1436,1437,1438,1460],"table",{},[1439,1440,1441],"thead",{},[1442,1443,1444,1448,1451,1454,1457],"tr",{},[1445,1446,1447],"th",{},"Level",[1445,1449,1450],{},"Dirty",[1445,1452,1453],{},"Non-rep",[1445,1455,1456],{},"Phantom",[1445,1458,1459],{},"Serial. anomaly",[1461,1462,1463,1478,1496,1510],"tbody",{},[1442,1464,1465,1469,1472,1474,1476],{},[1466,1467,1468],"td",{},"Read Uncommitted",[1466,1470,1471],{},"(giống Read Committed trong PG)",[1466,1473],{},[1466,1475],{},[1466,1477],{},[1442,1479,1480,1486,1489,1492,1494],{},[1466,1481,1482,1485],{},[587,1483,1484],{},"Read Committed"," (default)",[1466,1487,1488],{},"❌",[1466,1490,1491],{},"✅",[1466,1493,1491],{},[1466,1495,1491],{},[1442,1497,1498,1501,1503,1505,1508],{},[1466,1499,1500],{},"Repeatable Read",[1466,1502,1488],{},[1466,1504,1488],{},[1466,1506,1507],{},"❌ (nhờ MVCC)",[1466,1509,1491],{},[1442,1511,1512,1515,1517,1519,1521],{},[1466,1513,1514],{},"Serializable",[1466,1516,1488],{},[1466,1518,1488],{},[1466,1520,1488],{},[1466,1522,1488],{},[459,1524,1526],{"className":461,"code":1525,"language":463,"meta":464,"style":464},"SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;\nBEGIN;\n...\nCOMMIT;\n",[436,1527,1528,1533,1537,1542],{"__ignoreMap":464},[468,1529,1530],{"class":470,"line":471},[468,1531,1532],{},"SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;\n",[468,1534,1535],{"class":470,"line":477},[468,1536,1324],{},[468,1538,1539],{"class":470,"line":483},[468,1540,1541],{},"...\n",[468,1543,1544],{"class":470,"line":489},[468,1545,1339],{},[581,1547,1549,1554],{"color":1103,"icon":1548},"i-lucide-info",[432,1550,1551],{},[587,1552,1553],{},"Khác biệt Postgres vs SQL Server:",[784,1555,1556,1563,1569],{},[787,1557,1558,1559,1562],{},"Postgres ",[587,1560,1561],{},"không có dirty read"," thậm chí ở Read Uncommitted (vì MVCC).",[787,1564,1565,1566,808],{},"Postgres Repeatable Read = snapshot suốt transaction, ",[587,1567,1568],{},"bao luôn phantom",[787,1570,1571,1572,1575],{},"Postgres Serializable dùng ",[587,1573,1574],{},"SSI (Serializable Snapshot Isolation)"," — ít block, optimistic.",[427,1577,1579],{"id":1578},"_11-deadlock","11. Deadlock",[432,1581,1582,1583,1586],{},"Tương tự SQL Server. Postgres tự detect và abort 1 transaction (",[436,1584,1585],{},"deadlock_timeout"," default 1s).",[459,1588,1590],{"className":461,"code":1589,"language":463,"meta":464,"style":464},"-- Bật log\nSET log_lock_waits = on;\nSET deadlock_timeout = '1s';\n",[436,1591,1592,1597,1602],{"__ignoreMap":464},[468,1593,1594],{"class":470,"line":471},[468,1595,1596],{},"-- Bật log\n",[468,1598,1599],{"class":470,"line":477},[468,1600,1601],{},"SET log_lock_waits = on;\n",[468,1603,1604],{"class":470,"line":483},[468,1605,1606],{},"SET deadlock_timeout = '1s';\n",[427,1608,1610],{"id":1609},"_12-explain-query-planning","12. EXPLAIN & query planning",[454,1612,1614],{"id":1613},"cú-pháp","Cú pháp",[459,1616,1618],{"className":461,"code":1617,"language":463,"meta":464,"style":464},"EXPLAIN SELECT * FROM orders WHERE user_id = 1;\n\nEXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)\nSELECT * FROM orders WHERE user_id = 1;\n",[436,1619,1620,1625,1629,1634],{"__ignoreMap":464},[468,1621,1622],{"class":470,"line":471},[468,1623,1624],{},"EXPLAIN SELECT * FROM orders WHERE user_id = 1;\n",[468,1626,1627],{"class":470,"line":477},[468,1628,499],{"emptyLinePlaceholder":498},[468,1630,1631],{"class":470,"line":483},[468,1632,1633],{},"EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)\n",[468,1635,1636],{"class":470,"line":489},[468,1637,1638],{},"SELECT * FROM orders WHERE user_id = 1;\n",[432,1640,1641,1644,1645,1648],{},[436,1642,1643],{},"ANALYZE"," thực sự chạy query và đo time. ",[436,1646,1647],{},"BUFFERS"," show số page đọc.",[454,1650,1652],{"id":1651},"node-thường-gặp","Node thường gặp",[1436,1654,1655,1665],{},[1439,1656,1657],{},[1442,1658,1659,1662],{},[1445,1660,1661],{},"Node",[1445,1663,1664],{},"Ý nghĩa",[1461,1666,1667,1677,1687,1697,1711,1721,1731,1741,1751],{},[1442,1668,1669,1674],{},[1466,1670,1671],{},[587,1672,1673],{},"Seq Scan",[1466,1675,1676],{},"Full table scan — chậm với bảng lớn",[1442,1678,1679,1684],{},[1466,1680,1681],{},[587,1682,1683],{},"Index Scan",[1466,1685,1686],{},"Dùng index, lookup heap",[1442,1688,1689,1694],{},[1466,1690,1691],{},[587,1692,1693],{},"Index Only Scan",[1466,1695,1696],{},"Dùng index, không cần heap — tốt nhất",[1442,1698,1699,1708],{},[1466,1700,1701,1704,1705],{},[587,1702,1703],{},"Bitmap Index Scan"," + ",[587,1706,1707],{},"Bitmap Heap Scan",[1466,1709,1710],{},"Tốt khi nhiều row match một index",[1442,1712,1713,1718],{},[1466,1714,1715],{},[587,1716,1717],{},"Nested Loop",[1466,1719,1720],{},"JOIN row-by-row",[1442,1722,1723,1728],{},[1466,1724,1725],{},[587,1726,1727],{},"Hash Join",[1466,1729,1730],{},"JOIN bằng hash",[1442,1732,1733,1738],{},[1466,1734,1735],{},[587,1736,1737],{},"Merge Join",[1466,1739,1740],{},"JOIN trên 2 nguồn đã sort",[1442,1742,1743,1748],{},[1466,1744,1745],{},[587,1746,1747],{},"Sort",[1466,1749,1750],{},"Sắp xếp — đắt",[1442,1752,1753,1758],{},[1466,1754,1755],{},[587,1756,1757],{},"Gather\u002FParallel",[1466,1759,1760],{},"Parallel query",[454,1762,1764,1765],{"id":1763},"cost-startup_costtotal_cost","Cost = ",[436,1766,1767],{},"startup_cost..total_cost",[432,1769,1770],{},"So sánh cost giữa các plan để chọn tối ưu hơn.",[454,1772,1774],{"id":1773},"postgres-18-b-tree-skip-scan","Postgres 18 — B-tree Skip Scan",[581,1776,585,1777,1780,1781,1784,1785,1788,1789,1792,1793,1796],{"color":583,"icon":584},[587,1778,1779],{},"PG 18 B-tree Skip Scan."," Khi ",[436,1782,1783],{},"DISTINCT"," hoặc ",[436,1786,1787],{},"GROUP BY"," trên cột đầu tiên của composite index, planner có thể chọn ",[436,1790,1791],{},"Skip Scan"," thay vì Seq Scan. Thấy trong EXPLAIN: ",[436,1794,1795],{},"-> Index Only Scan using idx_abc on tab (actual ... skip=...)",". Không cần thay đổi SQL — planner tự xài khi có lợi.",[454,1798,1800],{"id":1799},"postgres-19-memoize-estimates-trong-explain","Postgres 19 — Memoize estimates trong EXPLAIN",[459,1802,1804],{"className":461,"code":1803,"language":463,"meta":464,"style":464},"-- Memoize là cache node trong Nested Loop: nhớ kết quả subquery theo key\n-- Postgres 19 hiển thị thêm thông tin ước lượng:\nEXPLAIN (ANALYZE)\nSELECT * FROM orders o\nJOIN LATERAL (\n    SELECT * FROM users u WHERE u.id = o.user_id\n) u ON true;\n",[436,1805,1806,1811,1816,1821,1826,1831,1836],{"__ignoreMap":464},[468,1807,1808],{"class":470,"line":471},[468,1809,1810],{},"-- Memoize là cache node trong Nested Loop: nhớ kết quả subquery theo key\n",[468,1812,1813],{"class":470,"line":477},[468,1814,1815],{},"-- Postgres 19 hiển thị thêm thông tin ước lượng:\n",[468,1817,1818],{"class":470,"line":483},[468,1819,1820],{},"EXPLAIN (ANALYZE)\n",[468,1822,1823],{"class":470,"line":489},[468,1824,1825],{},"SELECT * FROM orders o\n",[468,1827,1828],{"class":470,"line":495},[468,1829,1830],{},"JOIN LATERAL (\n",[468,1832,1833],{"class":470,"line":502},[468,1834,1835],{},"    SELECT * FROM users u WHERE u.id = o.user_id\n",[468,1837,1838],{"class":470,"line":508},[468,1839,1840],{},") u ON true;\n",[459,1842,1847],{"className":1843,"code":1845,"language":1846},[1844],"language-text","->  Memoize  (cost=1.25..123.50 rows=10 width=100)\n      Cache Key: o.user_id\n      Estimates: capacity=2 distinct keys=2 lookups=1000 hit percent=99.80%\n      Hits: 998  Misses: 2  Evictions: 0\n","text",[436,1848,1845],{"__ignoreMap":464},[581,1850,585,1851,947,1854,439,1857,439,1860,1863,1864,1866,1867,1869,1870,1873],{"color":1103,"icon":584},[587,1852,1853],{},"PG 19 EXPLAIN Memoize.",[436,1855,1856],{},"capacity",[436,1858,1859],{},"distinct keys",[436,1861,1862],{},"hit percent"," đều là ước lượng — planner dùng để quyết định có dùng Memoize hay không. ",[436,1865,1862],{}," càng cao càng có lợi. Thấy rõ hơn qua ",[436,1868,1643],{}," với ",[436,1871,1872],{},"Hits\u002FMisses\u002FEvictions"," thực tế.",[454,1875,1877],{"id":1876},"postgres-18-async-io-accelerate","Postgres 18 — Async I\u002FO accelerate",[581,1879,1880,1881,1884],{"color":1103,"icon":584},"⭐ Postgres 18 release ghi nhận ",[587,1882,1883],{},"đến 3× faster"," cho Sequential Scan và Bitmap Heap Scan nhờ AIO subsystem. Workload IO-heavy nâng cấp lên 18 là quà free.",[427,1886,1888],{"id":1887},"_13-vacuum-analyze","13. VACUUM & ANALYZE",[459,1890,1892],{"className":461,"code":1891,"language":463,"meta":464,"style":464},"-- Manual\nVACUUM ANALYZE orders;\nVACUUM FULL orders;          -- rebuild bảng, lock dài — chỉ làm khi rất fragment\n\n-- Statistics riêng\nANALYZE orders;\n\n-- Auto-vacuum config (postgresql.conf)\nautovacuum = on\nautovacuum_naptime = 1min\n",[436,1893,1894,1899,1904,1909,1913,1918,1923,1927,1932,1937],{"__ignoreMap":464},[468,1895,1896],{"class":470,"line":471},[468,1897,1898],{},"-- Manual\n",[468,1900,1901],{"class":470,"line":477},[468,1902,1903],{},"VACUUM ANALYZE orders;\n",[468,1905,1906],{"class":470,"line":483},[468,1907,1908],{},"VACUUM FULL orders;          -- rebuild bảng, lock dài — chỉ làm khi rất fragment\n",[468,1910,1911],{"class":470,"line":489},[468,1912,499],{"emptyLinePlaceholder":498},[468,1914,1915],{"class":470,"line":495},[468,1916,1917],{},"-- Statistics riêng\n",[468,1919,1920],{"class":470,"line":502},[468,1921,1922],{},"ANALYZE orders;\n",[468,1924,1925],{"class":470,"line":508},[468,1926,499],{"emptyLinePlaceholder":498},[468,1928,1929],{"class":470,"line":558},[468,1930,1931],{},"-- Auto-vacuum config (postgresql.conf)\n",[468,1933,1934],{"class":470,"line":564},[468,1935,1936],{},"autovacuum = on\n",[468,1938,1939],{"class":470,"line":570},[468,1940,1941],{},"autovacuum_naptime = 1min\n",[581,1943,1944,1952],{"color":583,"icon":584},[432,1945,585,1946,947,1949],{},[587,1947,1948],{},"Câu PV:",[1412,1950,1951],{},"\"VACUUM trong Postgres làm gì?\"",[1416,1953,1954],{},[432,1955,1956],{},"\"VACUUM reclaim space từ row dead (đã DELETE hoặc UPDATE cũ trong MVCC). Auto-vacuum chạy nền. VACUUM FULL rebuild bảng từ đầu (lock dài), VACUUM thường không lock. ANALYZE cập nhật statistics cho planner.\"",[427,1958,1960],{"id":1959},"_14-sqlpgq-property-graph-queries-pg-19","14. SQL\u002FPGQ Property Graph Queries (PG 19)",[581,1962,585,1963,1966,1967,1970],{"color":583,"icon":584},[587,1964,1965],{},"Tính năng lớn nhất PG 19."," SQL\u002FPGQ cho phép viết graph query (pattern matching kiểu Cypher) trên chính bảng quan hệ hiện có — ",[587,1968,1969],{},"không extension, không storage engine mới, không migrate dữ liệu."," Chuẩn SQL:2023.",[454,1972,1974],{"id":1973},"khái-niệm","Khái niệm",[432,1976,1977,1978,1981,1982,1985],{},"Property Graph là view logic trên bảng có sẵn: bảng là ",[587,1979,1980],{},"VERTEX"," (đỉnh), quan hệ khóa ngoại là ",[587,1983,1984],{},"EDGE"," (cạnh). Postgres rewrite graph query thành relational operation thông thường, dùng index có sẵn.",[454,1987,1614],{"id":1988},"cú-pháp-1",[459,1990,1992],{"className":461,"code":1991,"language":463,"meta":464,"style":464},"-- 1. Định nghĩa graph từ bảng có sẵn\nCREATE PROPERTY GRAPH social_graph\n  VERTEX TABLES (users LABEL person PROPERTIES (id, name, city))\n  EDGE TABLES (\n    follows\n      SOURCE KEY (follower_id) REFERENCES users (id)\n      DESTINATION KEY (followed_id) REFERENCES users (id)\n      LABEL follows\n  );\n\n-- 2. Query bằng GRAPH_TABLE\nSELECT * FROM GRAPH_TABLE (social_graph\n    MATCH (a IS person WHERE a.name = 'Alice')\n          -[IS follows]->(b IS person)\n          -[IS follows]->(c IS person)\n    COLUMNS (b.name AS friend, c.name AS friend_of_friend)\n);\n",[436,1993,1994,1999,2004,2009,2014,2019,2024,2029,2034,2039,2043,2048,2053,2058,2063,2068,2073],{"__ignoreMap":464},[468,1995,1996],{"class":470,"line":471},[468,1997,1998],{},"-- 1. Định nghĩa graph từ bảng có sẵn\n",[468,2000,2001],{"class":470,"line":477},[468,2002,2003],{},"CREATE PROPERTY GRAPH social_graph\n",[468,2005,2006],{"class":470,"line":483},[468,2007,2008],{},"  VERTEX TABLES (users LABEL person PROPERTIES (id, name, city))\n",[468,2010,2011],{"class":470,"line":489},[468,2012,2013],{},"  EDGE TABLES (\n",[468,2015,2016],{"class":470,"line":495},[468,2017,2018],{},"    follows\n",[468,2020,2021],{"class":470,"line":502},[468,2022,2023],{},"      SOURCE KEY (follower_id) REFERENCES users (id)\n",[468,2025,2026],{"class":470,"line":508},[468,2027,2028],{},"      DESTINATION KEY (followed_id) REFERENCES users (id)\n",[468,2030,2031],{"class":470,"line":558},[468,2032,2033],{},"      LABEL follows\n",[468,2035,2036],{"class":470,"line":564},[468,2037,2038],{},"  );\n",[468,2040,2041],{"class":470,"line":570},[468,2042,499],{"emptyLinePlaceholder":498},[468,2044,2045],{"class":470,"line":576},[468,2046,2047],{},"-- 2. Query bằng GRAPH_TABLE\n",[468,2049,2050],{"class":470,"line":764},[468,2051,2052],{},"SELECT * FROM GRAPH_TABLE (social_graph\n",[468,2054,2055],{"class":470,"line":912},[468,2056,2057],{},"    MATCH (a IS person WHERE a.name = 'Alice')\n",[468,2059,2060],{"class":470,"line":917},[468,2061,2062],{},"          -[IS follows]->(b IS person)\n",[468,2064,2065],{"class":470,"line":923},[468,2066,2067],{},"          -[IS follows]->(c IS person)\n",[468,2069,2070],{"class":470,"line":928},[468,2071,2072],{},"    COLUMNS (b.name AS friend, c.name AS friend_of_friend)\n",[468,2074,2075],{"class":470,"line":933},[468,2076,2077],{},");\n",[454,2079,2081],{"id":2080},"ví-dụ-nâng-cao-kết-hợp-với-sql-thường","Ví dụ nâng cao — kết hợp với SQL thường",[459,2083,2085],{"className":461,"code":2084,"language":463,"meta":464,"style":464},"-- GRAPH_TABLE compose với JOIN, aggregate, CTE như bảng thường\nWITH fof AS (\n    SELECT * FROM GRAPH_TABLE (social_graph\n        MATCH (a IS person WHERE a.name = 'Alice')\n              -[IS follows]->(b IS person)\n              -[IS follows]->(c IS person)\n        COLUMNS (c.id AS fof_id, c.name AS fof_name)\n    )\n)\nSELECT fof_name, COUNT(*) AS order_count\nFROM fof JOIN orders o ON o.user_id = fof_id\nGROUP BY fof_name\nORDER BY order_count DESC;\n",[436,2086,2087,2092,2097,2102,2107,2112,2117,2122,2127,2131,2136,2141,2146],{"__ignoreMap":464},[468,2088,2089],{"class":470,"line":471},[468,2090,2091],{},"-- GRAPH_TABLE compose với JOIN, aggregate, CTE như bảng thường\n",[468,2093,2094],{"class":470,"line":477},[468,2095,2096],{},"WITH fof AS (\n",[468,2098,2099],{"class":470,"line":483},[468,2100,2101],{},"    SELECT * FROM GRAPH_TABLE (social_graph\n",[468,2103,2104],{"class":470,"line":489},[468,2105,2106],{},"        MATCH (a IS person WHERE a.name = 'Alice')\n",[468,2108,2109],{"class":470,"line":495},[468,2110,2111],{},"              -[IS follows]->(b IS person)\n",[468,2113,2114],{"class":470,"line":502},[468,2115,2116],{},"              -[IS follows]->(c IS person)\n",[468,2118,2119],{"class":470,"line":508},[468,2120,2121],{},"        COLUMNS (c.id AS fof_id, c.name AS fof_name)\n",[468,2123,2124],{"class":470,"line":558},[468,2125,2126],{},"    )\n",[468,2128,2129],{"class":470,"line":564},[468,2130,625],{},[468,2132,2133],{"class":470,"line":570},[468,2134,2135],{},"SELECT fof_name, COUNT(*) AS order_count\n",[468,2137,2138],{"class":470,"line":576},[468,2139,2140],{},"FROM fof JOIN orders o ON o.user_id = fof_id\n",[468,2142,2143],{"class":470,"line":764},[468,2144,2145],{},"GROUP BY fof_name\n",[468,2147,2148],{"class":470,"line":912},[468,2149,2150],{},"ORDER BY order_count DESC;\n",[459,2152,2154],{"className":461,"code":2153,"language":463,"meta":464,"style":464},"-- Tạo graph từ JOIN\nCREATE PROPERTY GRAPH user_order_graph\n  VERTEX TABLES (\n    users LABEL user PROPERTIES (id, name),\n    orders LABEL \"order\" PROPERTIES (id, total, status)\n  )\n  EDGE TABLES (\n    -- Edge implicit từ FK\n    orders AS placed\n      SOURCE KEY (user_id) REFERENCES users (id)\n      LABEL placed_by\n  );\n",[436,2155,2156,2161,2166,2171,2176,2181,2186,2190,2195,2200,2205,2210],{"__ignoreMap":464},[468,2157,2158],{"class":470,"line":471},[468,2159,2160],{},"-- Tạo graph từ JOIN\n",[468,2162,2163],{"class":470,"line":477},[468,2164,2165],{},"CREATE PROPERTY GRAPH user_order_graph\n",[468,2167,2168],{"class":470,"line":483},[468,2169,2170],{},"  VERTEX TABLES (\n",[468,2172,2173],{"class":470,"line":489},[468,2174,2175],{},"    users LABEL user PROPERTIES (id, name),\n",[468,2177,2178],{"class":470,"line":495},[468,2179,2180],{},"    orders LABEL \"order\" PROPERTIES (id, total, status)\n",[468,2182,2183],{"class":470,"line":502},[468,2184,2185],{},"  )\n",[468,2187,2188],{"class":470,"line":508},[468,2189,2013],{},[468,2191,2192],{"class":470,"line":558},[468,2193,2194],{},"    -- Edge implicit từ FK\n",[468,2196,2197],{"class":470,"line":564},[468,2198,2199],{},"    orders AS placed\n",[468,2201,2202],{"class":470,"line":570},[468,2203,2204],{},"      SOURCE KEY (user_id) REFERENCES users (id)\n",[468,2206,2207],{"class":470,"line":576},[468,2208,2209],{},"      LABEL placed_by\n",[468,2211,2212],{"class":470,"line":764},[468,2213,2038],{},[454,2215,2217],{"id":2216},"giới-hạn-hiện-tại","Giới hạn hiện tại",[581,2219,2220,2223,2224,439,2227,2230,2231,2234,2235],{"color":1103,"icon":1548},[587,2221,2222],{},"PG 19 (initial):"," Fixed-depth pattern matching (số hop cố định). Variable-length path (",[436,2225,2226],{},"-[IS follows]->+",[436,2228,2229],{},"-[IS follows]->*"," hay ",[436,2232,2233],{},"-[IS follows]->{2,4}",") sẽ có trong phiên bản sau. Không thay thế được Neo4j\u002FJanusGraph nếu cần graph chuyên sâu, nhưng đủ cho bài toán \"friend-of-friend\", \"mutual connection\", \"path detection\" đơn giản — ",[587,2236,2237],{},"ngay trên bảng quan hệ hiện tại, zero migration.",[581,2239,2240,2247],{"color":583,"icon":584},[432,2241,585,2242,947,2244],{},[587,2243,1948],{},[1412,2245,2246],{},"\"Postgres hỗ trợ graph query chưa — có cần cài extension không?\"",[1416,2248,2249],{},[432,2250,2251,2252,2255,2256,2259],{},"\"Từ PG 19, hỗ trợ chuẩn SQL\u002FPGQ ngay trong core. ",[436,2253,2254],{},"CREATE PROPERTY GRAPH"," định nghĩa graph từ bảng có sẵn, ",[436,2257,2258],{},"GRAPH_TABLE"," để query. Engine tự rewrite thành relational operation, không cần extension, không cần storage mới. Kết quả compose với JOIN, aggregate, CTE như bảng thường. Fixed-depth hiện tại, variable-length sẽ có trong tương lai.\"",[581,2261,2263,2264],{"color":1103,"icon":2262},"i-lucide-arrow-right","Tiếp theo: ",[2265,2266,2267],"a",{"href":213},"Đặc thù Postgres & Performance",[2269,2270,2271],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":464,"searchDepth":477,"depth":477,"links":2273},[2274,2277,2278,2283,2286,2287,2288,2289,2290,2291,2295,2296,2305,2306],{"id":429,"depth":477,"text":430,"children":2275},[2276],{"id":456,"depth":483,"text":457},{"id":514,"depth":477,"text":515},{"id":600,"depth":477,"text":601,"children":2279},[2280,2281,2282],{"id":604,"depth":483,"text":605},{"id":643,"depth":483,"text":644},{"id":702,"depth":483,"text":703},{"id":770,"depth":477,"text":771,"children":2284},[2285],{"id":845,"depth":483,"text":846},{"id":1055,"depth":477,"text":1056},{"id":1074,"depth":477,"text":1075},{"id":1110,"depth":477,"text":1111},{"id":1185,"depth":477,"text":1186},{"id":1251,"depth":477,"text":1252},{"id":1313,"depth":477,"text":1314,"children":2292},[2293,2294],{"id":1402,"depth":483,"text":1403},{"id":1433,"depth":483,"text":1434},{"id":1578,"depth":477,"text":1579},{"id":1609,"depth":477,"text":1610,"children":2297},[2298,2299,2300,2302,2303,2304],{"id":1613,"depth":483,"text":1614},{"id":1651,"depth":483,"text":1652},{"id":1763,"depth":483,"text":2301},"Cost = startup_cost..total_cost",{"id":1773,"depth":483,"text":1774},{"id":1799,"depth":483,"text":1800},{"id":1876,"depth":483,"text":1877},{"id":1887,"depth":477,"text":1888},{"id":1959,"depth":477,"text":1960,"children":2307},[2308,2309,2310,2311],{"id":1973,"depth":483,"text":1974},{"id":1988,"depth":483,"text":1614},{"id":2080,"depth":483,"text":2081},{"id":2216,"depth":483,"text":2217},"JOIN, LATERAL, CTE recursive, window function, MVCC, transaction, isolation, EXPLAIN — gốc Postgres.","md",null,{},{"title":183,"icon":186},{"title":422,"description":2312},"wSNPiPcFZFCh2IN-RxZH49dZYzrkOsdJN2ostm2r-_o",[2320,2322],{"title":178,"path":207,"stem":208,"description":2321,"icon":181,"children":-1},"Kiểu dữ liệu, DDL, DML, UPSERT (ON CONFLICT), RETURNING, GROUP BY ALL, FOR PORTION OF — gốc cho PostgreSQL 18 & 19.",{"title":188,"path":213,"stem":214,"description":2323,"icon":191,"children":-1},"Feature riêng Postgres — JSONB, array, range, extension (pgvector, PostGIS, pg_trgm), partial\u002Fexpression index, performance tuning.",1783490365483]