[{"data":1,"prerenderedAt":3850},["ShallowReactive",2],{"navigation_docs":3,"-tu-hoc-database-mysql-truy-van-nang-cao":420,"-tu-hoc-database-mysql-truy-van-nang-cao-surround":3845},[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":3838,"extension":3839,"links":3840,"meta":3841,"navigation":3842,"path":235,"seo":3843,"stem":236,"__hash__":3844},"docs\u002F2.tu-hoc\u002F1.database\u002F4.mysql\u002F3.truy-van-nang-cao.md","Truy vấn MySQL nâng cao",{"type":424,"value":425,"toc":3775},"minimark",[426,431,457,486,491,506,510,517,591,600,604,608,615,655,659,673,727,752,756,763,846,850,944,958,964,968,987,1011,1015,1019,1053,1057,1168,1175,1179,1261,1264,1268,1369,1373,1443,1465,1478,1482,1589,1593,1596,1666,1670,1673,1767,1829,1833,1924,1928,2019,2023,2125,2129,2185,2201,2205,2234,2255,2259,2262,2266,2319,2323,2362,2366,2414,2418,2457,2474,2481,2485,2489,2513,2538,2542,2594,2598,2604,2668,2734,2743,2747,2805,2809,2886,2898,2902,2906,2973,2977,2997,3001,3020,3049,3053,3078,3093,3097,3147,3151,3180,3183,3187,3211,3215,3321,3325,3333,3340,3344,3350,3354,3361,3392,3396,3474,3478,3498,3502,3560,3564,3594,3642,3664,3668,3686,3752,3765,3771],[427,428,430],"h2",{"id":429},"_1-join-giống-chuẩn","1. JOIN — giống chuẩn",[432,433,434,438,439,438,442,438,445,448,449,456],"p",{},[435,436,437],"code",{},"INNER",", ",[435,440,441],{},"LEFT",[435,443,444],{},"RIGHT",[435,446,447],{},"CROSS"," y hệt SQL Server \u002F Postgres. ",[450,451,452,453],"strong",{},"MySQL không có ",[435,454,455],{},"FULL OUTER JOIN"," — phải mô phỏng:",[458,459,464],"pre",{"className":460,"code":461,"language":462,"meta":463,"style":463},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","SELECT * FROM a LEFT JOIN b ON a.id = b.a_id\nUNION\nSELECT * FROM a RIGHT JOIN b ON a.id = b.a_id;\n","sql","",[435,465,466,474,480],{"__ignoreMap":463},[467,468,471],"span",{"class":469,"line":470},"line",1,[467,472,473],{},"SELECT * FROM a LEFT JOIN b ON a.id = b.a_id\n",[467,475,477],{"class":469,"line":476},2,[467,478,479],{},"UNION\n",[467,481,483],{"class":469,"line":482},3,[467,484,485],{},"SELECT * FROM a RIGHT JOIN b ON a.id = b.a_id;\n",[487,488,490],"h3",{"id":489},"straight_join-ép-thứ-tự","STRAIGHT_JOIN — ép thứ tự",[458,492,494],{"className":460,"code":493,"language":462,"meta":463,"style":463},"-- Khi optimizer chọn thứ tự sai, ép join theo thứ tự viết\nSELECT STRAIGHT_JOIN * FROM small s JOIN big b ON b.s_id = s.id;\n",[435,495,496,501],{"__ignoreMap":463},[467,497,498],{"class":469,"line":470},[467,499,500],{},"-- Khi optimizer chọn thứ tự sai, ép join theo thứ tự viết\n",[467,502,503],{"class":469,"line":476},[467,504,505],{},"SELECT STRAIGHT_JOIN * FROM small s JOIN big b ON b.s_id = s.id;\n",[427,507,509],{"id":508},"_2-subquery","2. Subquery",[432,511,512,513,516],{},"Cú pháp chuẩn. ",[450,514,515],{},"MySQL trước đây correlated subquery rất chậm",", từ 8.0 và đặc biệt Hypergraph Optimizer (9.7 Community) đã cải thiện nhiều.",[458,518,520],{"className":460,"code":519,"language":462,"meta":463,"style":463},"-- Scalar\nSELECT name, (SELECT COUNT(*) FROM orders WHERE user_id = u.id) AS cnt\nFROM users u;\n\n-- EXISTS\nSELECT * FROM users u\nWHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);\n\n-- Derived table (bắt buộc alias!)\nSELECT * FROM (\n    SELECT user_id, SUM(total) total FROM orders GROUP BY user_id\n) t WHERE t.total > 10000000;\n",[435,521,522,527,532,537,544,550,556,562,567,573,579,585],{"__ignoreMap":463},[467,523,524],{"class":469,"line":470},[467,525,526],{},"-- Scalar\n",[467,528,529],{"class":469,"line":476},[467,530,531],{},"SELECT name, (SELECT COUNT(*) FROM orders WHERE user_id = u.id) AS cnt\n",[467,533,534],{"class":469,"line":482},[467,535,536],{},"FROM users u;\n",[467,538,540],{"class":469,"line":539},4,[467,541,543],{"emptyLinePlaceholder":542},true,"\n",[467,545,547],{"class":469,"line":546},5,[467,548,549],{},"-- EXISTS\n",[467,551,553],{"class":469,"line":552},6,[467,554,555],{},"SELECT * FROM users u\n",[467,557,559],{"class":469,"line":558},7,[467,560,561],{},"WHERE EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);\n",[467,563,565],{"class":469,"line":564},8,[467,566,543],{"emptyLinePlaceholder":542},[467,568,570],{"class":469,"line":569},9,[467,571,572],{},"-- Derived table (bắt buộc alias!)\n",[467,574,576],{"class":469,"line":575},10,[467,577,578],{},"SELECT * FROM (\n",[467,580,582],{"class":469,"line":581},11,[467,583,584],{},"    SELECT user_id, SUM(total) total FROM orders GROUP BY user_id\n",[467,586,588],{"class":469,"line":587},12,[467,589,590],{},") t WHERE t.total > 10000000;\n",[592,593,596,599],"callout",{"color":594,"icon":595},"primary","i-lucide-info",[450,597,598],{},"MySQL bắt buộc đặt alias"," cho derived table. Postgres và SQL Server không bắt buộc.",[427,601,603],{"id":602},"_3-derived-tables-lateral-8014","3. Derived tables & LATERAL (8.0.14+)",[487,605,607],{"id":606},"derived-table","Derived table",[432,609,610,611,614],{},"Derived table là subquery trong ",[435,612,613],{},"FROM"," clause. MySQL bắt buộc phải có alias:",[458,616,618],{"className":460,"code":617,"language":462,"meta":463,"style":463},"SELECT *\nFROM (\n    SELECT user_id, SUM(total) AS total\n    FROM orders\n    GROUP BY user_id\n) t\nWHERE t.total > 10000000;\n",[435,619,620,625,630,635,640,645,650],{"__ignoreMap":463},[467,621,622],{"class":469,"line":470},[467,623,624],{},"SELECT *\n",[467,626,627],{"class":469,"line":476},[467,628,629],{},"FROM (\n",[467,631,632],{"class":469,"line":482},[467,633,634],{},"    SELECT user_id, SUM(total) AS total\n",[467,636,637],{"class":469,"line":539},[467,638,639],{},"    FROM orders\n",[467,641,642],{"class":469,"line":546},[467,643,644],{},"    GROUP BY user_id\n",[467,646,647],{"class":469,"line":552},[467,648,649],{},") t\n",[467,651,652],{"class":469,"line":558},[467,653,654],{},"WHERE t.total > 10000000;\n",[487,656,658],{"id":657},"lateral-tham-chiếu-cột-từ-bảng-trước","LATERAL — tham chiếu cột từ bảng trước",[432,660,661,662,665,666,668,669,672],{},"Từ MySQL 8.0.14, ",[435,663,664],{},"LATERAL"," cho phép subquery trong ",[435,667,613],{}," hoặc ",[435,670,671],{},"JOIN"," tham chiếu đến cột của bảng phía trước — điều derived table thông thường không làm được:",[458,674,676],{"className":460,"code":675,"language":462,"meta":463,"style":463},"-- Lấy 3 đơn hàng gần nhất của mỗi user\nSELECT u.name, o.order_date, o.total\nFROM users u\nJOIN LATERAL (\n    SELECT order_date, total\n    FROM orders\n    WHERE user_id = u.id          -- ← tham chiếu u.id từ bảng ngoài\n    ORDER BY order_date DESC\n    LIMIT 3\n) o ON TRUE;\n",[435,677,678,683,688,693,698,703,707,712,717,722],{"__ignoreMap":463},[467,679,680],{"class":469,"line":470},[467,681,682],{},"-- Lấy 3 đơn hàng gần nhất của mỗi user\n",[467,684,685],{"class":469,"line":476},[467,686,687],{},"SELECT u.name, o.order_date, o.total\n",[467,689,690],{"class":469,"line":482},[467,691,692],{},"FROM users u\n",[467,694,695],{"class":469,"line":539},[467,696,697],{},"JOIN LATERAL (\n",[467,699,700],{"class":469,"line":546},[467,701,702],{},"    SELECT order_date, total\n",[467,704,705],{"class":469,"line":552},[467,706,639],{},[467,708,709],{"class":469,"line":558},[467,710,711],{},"    WHERE user_id = u.id          -- ← tham chiếu u.id từ bảng ngoài\n",[467,713,714],{"class":469,"line":564},[467,715,716],{},"    ORDER BY order_date DESC\n",[467,718,719],{"class":469,"line":569},[467,720,721],{},"    LIMIT 3\n",[467,723,724],{"class":469,"line":575},[467,725,726],{},") o ON TRUE;\n",[592,728,731,742],{"color":729,"icon":730},"warning","i-lucide-star",[432,732,733,734,737,738],{},"⭐ ",[450,735,736],{},"Câu PV:"," ",[739,740,741],"em",{},"\"LATERAL khác gì JOIN thường?\"",[743,744,745],"blockquote",{},[432,746,747,748,751],{},"\"JOIN thường không thể tham chiếu cột từ bảng bên trái trong subquery. LATERAL cho phép điều đó — giống ",[435,749,750],{},"CROSS APPLY"," trong SQL Server. Dùng để lấy top-N per group với LIMIT, hoặc gọi function với tham số từ mỗi row.\"",[487,753,755],{"id":754},"lateral-vs-window-function-cùng-bài-toán","LATERAL vs Window Function — cùng bài toán",[432,757,758,759,762],{},"Cùng bài toán \"top N per group\", LATERAL và ",[435,760,761],{},"ROW_NUMBER()"," cho kết quả giống nhau, nhưng LATERAL thường nhanh hơn khi N nhỏ và có index tốt (có thể dừng sớm):",[458,764,766],{"className":460,"code":765,"language":462,"meta":463,"style":463},"-- Cách 1: Window function (luôn scan toàn bộ partition)\nWITH ranked AS (\n    SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) rn\n    FROM orders\n)\nSELECT * FROM ranked WHERE rn \u003C= 3;\n\n-- Cách 2: LATERAL (có thể dừng sau khi lấy đủ 3 row)\nSELECT u.name, o.*\nFROM users u\nJOIN LATERAL (\n    SELECT * FROM orders\n    WHERE user_id = u.id\n    ORDER BY created_at DESC\n    LIMIT 3\n) o ON TRUE;\n",[435,767,768,773,778,783,787,792,797,801,806,811,815,819,824,830,836,841],{"__ignoreMap":463},[467,769,770],{"class":469,"line":470},[467,771,772],{},"-- Cách 1: Window function (luôn scan toàn bộ partition)\n",[467,774,775],{"class":469,"line":476},[467,776,777],{},"WITH ranked AS (\n",[467,779,780],{"class":469,"line":482},[467,781,782],{},"    SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) rn\n",[467,784,785],{"class":469,"line":539},[467,786,639],{},[467,788,789],{"class":469,"line":546},[467,790,791],{},")\n",[467,793,794],{"class":469,"line":552},[467,795,796],{},"SELECT * FROM ranked WHERE rn \u003C= 3;\n",[467,798,799],{"class":469,"line":558},[467,800,543],{"emptyLinePlaceholder":542},[467,802,803],{"class":469,"line":564},[467,804,805],{},"-- Cách 2: LATERAL (có thể dừng sau khi lấy đủ 3 row)\n",[467,807,808],{"class":469,"line":569},[467,809,810],{},"SELECT u.name, o.*\n",[467,812,813],{"class":469,"line":575},[467,814,692],{},[467,816,817],{"class":469,"line":581},[467,818,697],{},[467,820,821],{"class":469,"line":587},[467,822,823],{},"    SELECT * FROM orders\n",[467,825,827],{"class":469,"line":826},13,[467,828,829],{},"    WHERE user_id = u.id\n",[467,831,833],{"class":469,"line":832},14,[467,834,835],{},"    ORDER BY created_at DESC\n",[467,837,839],{"class":469,"line":838},15,[467,840,721],{},[467,842,844],{"class":469,"line":843},16,[467,845,726],{},[427,847,849],{"id":848},"_4-set-operations","4. Set operations",[458,851,853],{"className":460,"code":852,"language":462,"meta":463,"style":463},"-- UNION — loại bỏ duplicate (phải sort\u002Fdistinct → chậm hơn)\nSELECT email FROM customers\nUNION\nSELECT email FROM suppliers;\n\n-- UNION ALL — giữ tất cả row, kể cả duplicate (nhanh hơn)\nSELECT email FROM customers\nUNION ALL\nSELECT email FROM suppliers;\n\n-- INTERSECT — row xuất hiện trong CẢ 2 tập (MySQL 8.0.31+)\nSELECT email FROM customers\nINTERSECT\nSELECT email FROM suppliers;\n\n-- EXCEPT — row có trong tập 1 nhưng KHÔNG có trong tập 2 (MySQL 8.0.31+)\nSELECT email FROM customers\nEXCEPT\nSELECT email FROM banned;\n",[435,854,855,860,865,869,874,878,883,887,892,896,900,905,909,914,918,922,927,932,938],{"__ignoreMap":463},[467,856,857],{"class":469,"line":470},[467,858,859],{},"-- UNION — loại bỏ duplicate (phải sort\u002Fdistinct → chậm hơn)\n",[467,861,862],{"class":469,"line":476},[467,863,864],{},"SELECT email FROM customers\n",[467,866,867],{"class":469,"line":482},[467,868,479],{},[467,870,871],{"class":469,"line":539},[467,872,873],{},"SELECT email FROM suppliers;\n",[467,875,876],{"class":469,"line":546},[467,877,543],{"emptyLinePlaceholder":542},[467,879,880],{"class":469,"line":552},[467,881,882],{},"-- UNION ALL — giữ tất cả row, kể cả duplicate (nhanh hơn)\n",[467,884,885],{"class":469,"line":558},[467,886,864],{},[467,888,889],{"class":469,"line":564},[467,890,891],{},"UNION ALL\n",[467,893,894],{"class":469,"line":569},[467,895,873],{},[467,897,898],{"class":469,"line":575},[467,899,543],{"emptyLinePlaceholder":542},[467,901,902],{"class":469,"line":581},[467,903,904],{},"-- INTERSECT — row xuất hiện trong CẢ 2 tập (MySQL 8.0.31+)\n",[467,906,907],{"class":469,"line":587},[467,908,864],{},[467,910,911],{"class":469,"line":826},[467,912,913],{},"INTERSECT\n",[467,915,916],{"class":469,"line":832},[467,917,873],{},[467,919,920],{"class":469,"line":838},[467,921,543],{"emptyLinePlaceholder":542},[467,923,924],{"class":469,"line":843},[467,925,926],{},"-- EXCEPT — row có trong tập 1 nhưng KHÔNG có trong tập 2 (MySQL 8.0.31+)\n",[467,928,930],{"class":469,"line":929},17,[467,931,864],{},[467,933,935],{"class":469,"line":934},18,[467,936,937],{},"EXCEPT\n",[467,939,941],{"class":469,"line":940},19,[467,942,943],{},"SELECT email FROM banned;\n",[592,945,946,953],{"color":729,"icon":730},[432,947,733,948,737,950],{},[450,949,736],{},[739,951,952],{},"\"UNION và UNION ALL khác nhau thế nào? Khi nào dùng cái nào?\"",[743,954,955],{},[432,956,957],{},"\"UNION loại bỏ duplicate → phải sort hoặc hash distinct → chậm hơn. UNION ALL giữ tất cả → nhanh hơn. Luôn dùng UNION ALL trừ khi thực sự cần loại bỏ duplicate.\"",[592,959,960,963],{"color":594,"icon":595},[450,961,962],{},"INTERSECT và EXCEPT"," chỉ có từ MySQL 8.0.31+. Trước đó phải mô phỏng bằng JOIN hoặc NOT EXISTS \u002F NOT IN.",[487,965,967],{"id":966},"yêu-cầu-của-set-operations","Yêu cầu của set operations",[969,970,971,975,978,981],"ul",{},[972,973,974],"li",{},"Số cột phải bằng nhau giữa các SELECT",[972,976,977],{},"Kiểu dữ liệu tương thích ở mỗi vị trí",[972,979,980],{},"Tên cột lấy từ SELECT đầu tiên",[972,982,983,986],{},[435,984,985],{},"ORDER BY"," chỉ được đặt ở cuối cùng, áp dụng cho toàn bộ kết quả",[458,988,990],{"className":460,"code":989,"language":462,"meta":463,"style":463},"SELECT id, name, 'customer' AS type FROM customers\nUNION ALL\nSELECT id, name, 'supplier' FROM suppliers\nORDER BY type, name;\n",[435,991,992,997,1001,1006],{"__ignoreMap":463},[467,993,994],{"class":469,"line":470},[467,995,996],{},"SELECT id, name, 'customer' AS type FROM customers\n",[467,998,999],{"class":469,"line":476},[467,1000,891],{},[467,1002,1003],{"class":469,"line":482},[467,1004,1005],{},"SELECT id, name, 'supplier' FROM suppliers\n",[467,1007,1008],{"class":469,"line":539},[467,1009,1010],{},"ORDER BY type, name;\n",[427,1012,1014],{"id":1013},"_5-cte-common-table-expression-80","5. CTE — Common Table Expression (8.0+)",[487,1016,1018],{"id":1017},"cte-cơ-bản","CTE cơ bản",[458,1020,1022],{"className":460,"code":1021,"language":462,"meta":463,"style":463},"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",[435,1023,1024,1029,1034,1038,1043,1048],{"__ignoreMap":463},[467,1025,1026],{"class":469,"line":470},[467,1027,1028],{},"WITH high_value AS (\n",[467,1030,1031],{"class":469,"line":476},[467,1032,1033],{},"    SELECT * FROM orders WHERE total > 10000000\n",[467,1035,1036],{"class":469,"line":482},[467,1037,791],{},[467,1039,1040],{"class":469,"line":539},[467,1041,1042],{},"SELECT u.name, COUNT(*)\n",[467,1044,1045],{"class":469,"line":546},[467,1046,1047],{},"FROM high_value h JOIN users u ON u.id = h.user_id\n",[467,1049,1050],{"class":469,"line":552},[467,1051,1052],{},"GROUP BY u.name;\n",[487,1054,1056],{"id":1055},"nhiều-cte-trong-một-query","Nhiều CTE trong một query",[458,1058,1060],{"className":460,"code":1059,"language":462,"meta":463,"style":463},"WITH\n    active_users AS (\n        SELECT id, name FROM users WHERE status = 'active'\n    ),\n    user_totals AS (\n        SELECT user_id, SUM(total) AS total_spent\n        FROM orders\n        WHERE created_at >= '2025-01-01'\n        GROUP BY user_id\n    ),\n    ranked AS (\n        SELECT\n            au.name,\n            ut.total_spent,\n            RANK() OVER (ORDER BY ut.total_spent DESC) AS rk\n        FROM active_users au\n        JOIN user_totals ut ON ut.user_id = au.id\n    )\nSELECT name, total_spent, rk\nFROM ranked\nWHERE rk \u003C= 10;\n",[435,1061,1062,1067,1072,1077,1082,1087,1092,1097,1102,1107,1111,1116,1121,1126,1131,1136,1141,1146,1151,1156,1162],{"__ignoreMap":463},[467,1063,1064],{"class":469,"line":470},[467,1065,1066],{},"WITH\n",[467,1068,1069],{"class":469,"line":476},[467,1070,1071],{},"    active_users AS (\n",[467,1073,1074],{"class":469,"line":482},[467,1075,1076],{},"        SELECT id, name FROM users WHERE status = 'active'\n",[467,1078,1079],{"class":469,"line":539},[467,1080,1081],{},"    ),\n",[467,1083,1084],{"class":469,"line":546},[467,1085,1086],{},"    user_totals AS (\n",[467,1088,1089],{"class":469,"line":552},[467,1090,1091],{},"        SELECT user_id, SUM(total) AS total_spent\n",[467,1093,1094],{"class":469,"line":558},[467,1095,1096],{},"        FROM orders\n",[467,1098,1099],{"class":469,"line":564},[467,1100,1101],{},"        WHERE created_at >= '2025-01-01'\n",[467,1103,1104],{"class":469,"line":569},[467,1105,1106],{},"        GROUP BY user_id\n",[467,1108,1109],{"class":469,"line":575},[467,1110,1081],{},[467,1112,1113],{"class":469,"line":581},[467,1114,1115],{},"    ranked AS (\n",[467,1117,1118],{"class":469,"line":587},[467,1119,1120],{},"        SELECT\n",[467,1122,1123],{"class":469,"line":826},[467,1124,1125],{},"            au.name,\n",[467,1127,1128],{"class":469,"line":832},[467,1129,1130],{},"            ut.total_spent,\n",[467,1132,1133],{"class":469,"line":838},[467,1134,1135],{},"            RANK() OVER (ORDER BY ut.total_spent DESC) AS rk\n",[467,1137,1138],{"class":469,"line":843},[467,1139,1140],{},"        FROM active_users au\n",[467,1142,1143],{"class":469,"line":929},[467,1144,1145],{},"        JOIN user_totals ut ON ut.user_id = au.id\n",[467,1147,1148],{"class":469,"line":934},[467,1149,1150],{},"    )\n",[467,1152,1153],{"class":469,"line":940},[467,1154,1155],{},"SELECT name, total_spent, rk\n",[467,1157,1159],{"class":469,"line":1158},20,[467,1160,1161],{},"FROM ranked\n",[467,1163,1165],{"class":469,"line":1164},21,[467,1166,1167],{},"WHERE rk \u003C= 10;\n",[592,1169,1170,1171,1174],{"color":594,"icon":730},"⭐ Nhiều CTE trong cùng một query — mỗi CTE cách nhau bằng dấu phẩy, chỉ cần một từ khóa ",[435,1172,1173],{},"WITH"," ở đầu. Pattern này giúp query phức tạp dễ đọc, dễ debug hơn nhiều so với nested subquery.",[487,1176,1178],{"id":1177},"recursive-cte-sơ-đồ-tổ-chức-organizational-chart","Recursive CTE — sơ đồ tổ chức (organizational chart)",[458,1180,1182],{"className":460,"code":1181,"language":462,"meta":463,"style":463},"WITH RECURSIVE org AS (\n    -- Anchor: CEO (không có manager)\n    SELECT id, name, manager_id, 0 AS lvl,\n           CAST(name AS CHAR(500)) AS path\n    FROM employees WHERE manager_id IS NULL\n\n    UNION ALL\n\n    -- Recursive: nhân viên dưới quyền\n    SELECT e.id, e.name, e.manager_id, o.lvl + 1,\n           CONCAT(o.path, ' > ', e.name)\n    FROM employees e JOIN org o ON o.id = e.manager_id\n)\nSELECT id, name, lvl, path\nFROM org\nORDER BY path;\n",[435,1183,1184,1189,1194,1199,1204,1209,1213,1218,1222,1227,1232,1237,1242,1246,1251,1256],{"__ignoreMap":463},[467,1185,1186],{"class":469,"line":470},[467,1187,1188],{},"WITH RECURSIVE org AS (\n",[467,1190,1191],{"class":469,"line":476},[467,1192,1193],{},"    -- Anchor: CEO (không có manager)\n",[467,1195,1196],{"class":469,"line":482},[467,1197,1198],{},"    SELECT id, name, manager_id, 0 AS lvl,\n",[467,1200,1201],{"class":469,"line":539},[467,1202,1203],{},"           CAST(name AS CHAR(500)) AS path\n",[467,1205,1206],{"class":469,"line":546},[467,1207,1208],{},"    FROM employees WHERE manager_id IS NULL\n",[467,1210,1211],{"class":469,"line":552},[467,1212,543],{"emptyLinePlaceholder":542},[467,1214,1215],{"class":469,"line":558},[467,1216,1217],{},"    UNION ALL\n",[467,1219,1220],{"class":469,"line":564},[467,1221,543],{"emptyLinePlaceholder":542},[467,1223,1224],{"class":469,"line":569},[467,1225,1226],{},"    -- Recursive: nhân viên dưới quyền\n",[467,1228,1229],{"class":469,"line":575},[467,1230,1231],{},"    SELECT e.id, e.name, e.manager_id, o.lvl + 1,\n",[467,1233,1234],{"class":469,"line":581},[467,1235,1236],{},"           CONCAT(o.path, ' > ', e.name)\n",[467,1238,1239],{"class":469,"line":587},[467,1240,1241],{},"    FROM employees e JOIN org o ON o.id = e.manager_id\n",[467,1243,1244],{"class":469,"line":826},[467,1245,791],{},[467,1247,1248],{"class":469,"line":832},[467,1249,1250],{},"SELECT id, name, lvl, path\n",[467,1252,1253],{"class":469,"line":838},[467,1254,1255],{},"FROM org\n",[467,1257,1258],{"class":469,"line":843},[467,1259,1260],{},"ORDER BY path;\n",[432,1262,1263],{},"Kết quả: hiển thị toàn bộ cây tổ chức với level và đường dẫn từ CEO đến từng nhân viên.",[487,1265,1267],{"id":1266},"recursive-cte-bill-of-materials-bom","Recursive CTE — Bill of Materials (BOM)",[458,1269,1271],{"className":460,"code":1270,"language":462,"meta":463,"style":463},"-- Sản phẩm lắp ráp: tìm tất cả linh kiện con của sản phẩm #1\nWITH RECURSIVE bom AS (\n    -- Anchor: linh kiện trực tiếp\n    SELECT product_id, component_id, quantity, 1 AS lvl\n    FROM bill_of_materials\n    WHERE product_id = 1\n\n    UNION ALL\n\n    -- Recursive: linh kiện con của linh kiện\n    SELECT b.product_id, b.component_id, b.quantity, bom.lvl + 1\n    FROM bill_of_materials b\n    JOIN bom ON bom.component_id = b.product_id\n)\nSELECT b.lvl, b.product_id, p.name AS assembly,\n       b.component_id, c.name AS component, b.quantity\nFROM bom b\nJOIN products p ON p.id = b.product_id\nJOIN products c ON c.id = b.component_id\nORDER BY b.lvl, b.product_id;\n",[435,1272,1273,1278,1283,1288,1293,1298,1303,1307,1311,1315,1320,1325,1330,1335,1339,1344,1349,1354,1359,1364],{"__ignoreMap":463},[467,1274,1275],{"class":469,"line":470},[467,1276,1277],{},"-- Sản phẩm lắp ráp: tìm tất cả linh kiện con của sản phẩm #1\n",[467,1279,1280],{"class":469,"line":476},[467,1281,1282],{},"WITH RECURSIVE bom AS (\n",[467,1284,1285],{"class":469,"line":482},[467,1286,1287],{},"    -- Anchor: linh kiện trực tiếp\n",[467,1289,1290],{"class":469,"line":539},[467,1291,1292],{},"    SELECT product_id, component_id, quantity, 1 AS lvl\n",[467,1294,1295],{"class":469,"line":546},[467,1296,1297],{},"    FROM bill_of_materials\n",[467,1299,1300],{"class":469,"line":552},[467,1301,1302],{},"    WHERE product_id = 1\n",[467,1304,1305],{"class":469,"line":558},[467,1306,543],{"emptyLinePlaceholder":542},[467,1308,1309],{"class":469,"line":564},[467,1310,1217],{},[467,1312,1313],{"class":469,"line":569},[467,1314,543],{"emptyLinePlaceholder":542},[467,1316,1317],{"class":469,"line":575},[467,1318,1319],{},"    -- Recursive: linh kiện con của linh kiện\n",[467,1321,1322],{"class":469,"line":581},[467,1323,1324],{},"    SELECT b.product_id, b.component_id, b.quantity, bom.lvl + 1\n",[467,1326,1327],{"class":469,"line":587},[467,1328,1329],{},"    FROM bill_of_materials b\n",[467,1331,1332],{"class":469,"line":826},[467,1333,1334],{},"    JOIN bom ON bom.component_id = b.product_id\n",[467,1336,1337],{"class":469,"line":832},[467,1338,791],{},[467,1340,1341],{"class":469,"line":838},[467,1342,1343],{},"SELECT b.lvl, b.product_id, p.name AS assembly,\n",[467,1345,1346],{"class":469,"line":843},[467,1347,1348],{},"       b.component_id, c.name AS component, b.quantity\n",[467,1350,1351],{"class":469,"line":929},[467,1352,1353],{},"FROM bom b\n",[467,1355,1356],{"class":469,"line":934},[467,1357,1358],{},"JOIN products p ON p.id = b.product_id\n",[467,1360,1361],{"class":469,"line":940},[467,1362,1363],{},"JOIN products c ON c.id = b.component_id\n",[467,1365,1366],{"class":469,"line":1158},[467,1367,1368],{},"ORDER BY b.lvl, b.product_id;\n",[487,1370,1372],{"id":1371},"generate-sequence-calendar-number-table","Generate sequence (calendar, number table)",[458,1374,1376],{"className":460,"code":1375,"language":462,"meta":463,"style":463},"WITH RECURSIVE seq(n) AS (\n    SELECT 1\n    UNION ALL\n    SELECT n + 1 FROM seq WHERE n \u003C 100\n)\nSELECT * FROM seq;\n\n-- Generate calendar\nWITH RECURSIVE dates(d) AS (\n    SELECT '2025-01-01'\n    UNION ALL\n    SELECT d + INTERVAL 1 DAY FROM dates WHERE d \u003C '2025-12-31'\n)\nSELECT d FROM dates;\n",[435,1377,1378,1383,1388,1392,1397,1401,1406,1410,1415,1420,1425,1429,1434,1438],{"__ignoreMap":463},[467,1379,1380],{"class":469,"line":470},[467,1381,1382],{},"WITH RECURSIVE seq(n) AS (\n",[467,1384,1385],{"class":469,"line":476},[467,1386,1387],{},"    SELECT 1\n",[467,1389,1390],{"class":469,"line":482},[467,1391,1217],{},[467,1393,1394],{"class":469,"line":539},[467,1395,1396],{},"    SELECT n + 1 FROM seq WHERE n \u003C 100\n",[467,1398,1399],{"class":469,"line":546},[467,1400,791],{},[467,1402,1403],{"class":469,"line":552},[467,1404,1405],{},"SELECT * FROM seq;\n",[467,1407,1408],{"class":469,"line":558},[467,1409,543],{"emptyLinePlaceholder":542},[467,1411,1412],{"class":469,"line":564},[467,1413,1414],{},"-- Generate calendar\n",[467,1416,1417],{"class":469,"line":569},[467,1418,1419],{},"WITH RECURSIVE dates(d) AS (\n",[467,1421,1422],{"class":469,"line":575},[467,1423,1424],{},"    SELECT '2025-01-01'\n",[467,1426,1427],{"class":469,"line":581},[467,1428,1217],{},[467,1430,1431],{"class":469,"line":587},[467,1432,1433],{},"    SELECT d + INTERVAL 1 DAY FROM dates WHERE d \u003C '2025-12-31'\n",[467,1435,1436],{"class":469,"line":826},[467,1437,791],{},[467,1439,1440],{"class":469,"line":832},[467,1441,1442],{},"SELECT d FROM dates;\n",[592,1444,1445,1452],{"color":729,"icon":730},[432,1446,733,1447,737,1449],{},[450,1448,736],{},[739,1450,1451],{},"\"Recursive CTE dừng như thế nào? Làm sao tránh infinite loop?\"",[743,1453,1454],{},[432,1455,1456,1457,1460,1461,1464],{},"\"Recursive member trả về empty set là dừng. MySQL có ",[435,1458,1459],{},"cte_max_recursion_depth"," (default 1000) để giới hạn số vòng lặp — tăng lên nếu cần: ",[435,1462,1463],{},"SET SESSION cte_max_recursion_depth = 10000;",". Luôn đảm bảo điều kiện JOIN trong recursive member sẽ hội tụ.\"",[592,1466,1467,1473,1474,1477],{"color":594,"icon":595},[450,1468,452,1469,1472],{},[435,1470,1471],{},"MATERIALIZED"," hint"," như Postgres. Trong MySQL, CTE luôn được optimizer tự quyết định có materialize (lưu tạm vào bảng nhớ) hay merge thẳng vào query chính. Dùng ",[435,1475,1476],{},"EXPLAIN"," để kiểm tra.",[487,1479,1481],{"id":1480},"cte-kết-hợp-window-function","CTE kết hợp Window Function",[458,1483,1485],{"className":460,"code":1484,"language":462,"meta":463,"style":463},"WITH monthly_sales AS (\n    SELECT\n        DATE_FORMAT(created_at, '%Y-%m') AS month,\n        SUM(total) AS revenue\n    FROM orders\n    GROUP BY DATE_FORMAT(created_at, '%Y-%m')\n),\nwith_growth AS (\n    SELECT\n        month, revenue,\n        LAG(revenue) OVER (ORDER BY month) AS prev_revenue,\n        ROUND(\n            (revenue - LAG(revenue) OVER (ORDER BY month))\n            \u002F LAG(revenue) OVER (ORDER BY month) * 100,\n            2\n        ) AS growth_pct\n    FROM monthly_sales\n)\nSELECT * FROM with_growth\nWHERE growth_pct IS NOT NULL\nORDER BY month;\n",[435,1486,1487,1492,1497,1502,1507,1511,1516,1521,1526,1530,1535,1540,1545,1550,1555,1560,1565,1570,1574,1579,1584],{"__ignoreMap":463},[467,1488,1489],{"class":469,"line":470},[467,1490,1491],{},"WITH monthly_sales AS (\n",[467,1493,1494],{"class":469,"line":476},[467,1495,1496],{},"    SELECT\n",[467,1498,1499],{"class":469,"line":482},[467,1500,1501],{},"        DATE_FORMAT(created_at, '%Y-%m') AS month,\n",[467,1503,1504],{"class":469,"line":539},[467,1505,1506],{},"        SUM(total) AS revenue\n",[467,1508,1509],{"class":469,"line":546},[467,1510,639],{},[467,1512,1513],{"class":469,"line":552},[467,1514,1515],{},"    GROUP BY DATE_FORMAT(created_at, '%Y-%m')\n",[467,1517,1518],{"class":469,"line":558},[467,1519,1520],{},"),\n",[467,1522,1523],{"class":469,"line":564},[467,1524,1525],{},"with_growth AS (\n",[467,1527,1528],{"class":469,"line":569},[467,1529,1496],{},[467,1531,1532],{"class":469,"line":575},[467,1533,1534],{},"        month, revenue,\n",[467,1536,1537],{"class":469,"line":581},[467,1538,1539],{},"        LAG(revenue) OVER (ORDER BY month) AS prev_revenue,\n",[467,1541,1542],{"class":469,"line":587},[467,1543,1544],{},"        ROUND(\n",[467,1546,1547],{"class":469,"line":826},[467,1548,1549],{},"            (revenue - LAG(revenue) OVER (ORDER BY month))\n",[467,1551,1552],{"class":469,"line":832},[467,1553,1554],{},"            \u002F LAG(revenue) OVER (ORDER BY month) * 100,\n",[467,1556,1557],{"class":469,"line":838},[467,1558,1559],{},"            2\n",[467,1561,1562],{"class":469,"line":843},[467,1563,1564],{},"        ) AS growth_pct\n",[467,1566,1567],{"class":469,"line":929},[467,1568,1569],{},"    FROM monthly_sales\n",[467,1571,1572],{"class":469,"line":934},[467,1573,791],{},[467,1575,1576],{"class":469,"line":940},[467,1577,1578],{},"SELECT * FROM with_growth\n",[467,1580,1581],{"class":469,"line":1158},[467,1582,1583],{},"WHERE growth_pct IS NOT NULL\n",[467,1585,1586],{"class":469,"line":1164},[467,1587,1588],{},"ORDER BY month;\n",[427,1590,1592],{"id":1591},"_6-window-function-80","6. Window function (8.0+)",[432,1594,1595],{},"Tất cả function chuẩn ANSI được hỗ trợ:",[969,1597,1598,1622,1642],{},[972,1599,1600,737,1603,438,1606,438,1609,438,1612,438,1615,438,1618,1621],{},[450,1601,1602],{},"Ranking:",[435,1604,1605],{},"ROW_NUMBER",[435,1607,1608],{},"RANK",[435,1610,1611],{},"DENSE_RANK",[435,1613,1614],{},"NTILE",[435,1616,1617],{},"PERCENT_RANK",[435,1619,1620],{},"CUME_DIST",".",[972,1623,1624,737,1627,438,1630,438,1633,438,1636,438,1639,1621],{},[450,1625,1626],{},"Offset:",[435,1628,1629],{},"LAG",[435,1631,1632],{},"LEAD",[435,1634,1635],{},"FIRST_VALUE",[435,1637,1638],{},"LAST_VALUE",[435,1640,1641],{},"NTH_VALUE",[972,1643,1644,737,1647,438,1650,438,1653,438,1656,438,1659,1662,1663,1621],{},[450,1645,1646],{},"Aggregate:",[435,1648,1649],{},"SUM",[435,1651,1652],{},"AVG",[435,1654,1655],{},"COUNT",[435,1657,1658],{},"MIN",[435,1660,1661],{},"MAX"," với ",[435,1664,1665],{},"OVER",[487,1667,1669],{"id":1668},"frame-specification-rows-vs-range-vs-groups","Frame Specification — ROWS vs RANGE vs GROUPS",[432,1671,1672],{},"Frame xác định phạm vi row trong partition mà window function tính toán:",[458,1674,1676],{"className":460,"code":1675,"language":462,"meta":463,"style":463},"-- ROWS: đếm theo số dòng vật lý\nAVG(total) OVER (\n    PARTITION BY user_id\n    ORDER BY created_at\n    ROWS BETWEEN 6 PRECEDING AND CURRENT ROW    -- 7 dòng gần nhất\n)\n\n-- RANGE: đếm theo giá trị của ORDER BY column\nAVG(total) OVER (\n    PARTITION BY user_id\n    ORDER BY created_at\n    RANGE BETWEEN INTERVAL 7 DAY PRECEDING AND CURRENT ROW  -- 7 ngày gần nhất\n)\n\n-- GROUPS: đếm theo nhóm peer (các row có cùng giá trị ORDER BY)\nAVG(total) OVER (\n    PARTITION BY user_id\n    ORDER BY created_at\n    GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW  -- nhóm hiện tại + 1 nhóm trước\n)\n",[435,1677,1678,1683,1688,1693,1698,1703,1707,1711,1716,1720,1724,1728,1733,1737,1741,1746,1750,1754,1758,1763],{"__ignoreMap":463},[467,1679,1680],{"class":469,"line":470},[467,1681,1682],{},"-- ROWS: đếm theo số dòng vật lý\n",[467,1684,1685],{"class":469,"line":476},[467,1686,1687],{},"AVG(total) OVER (\n",[467,1689,1690],{"class":469,"line":482},[467,1691,1692],{},"    PARTITION BY user_id\n",[467,1694,1695],{"class":469,"line":539},[467,1696,1697],{},"    ORDER BY created_at\n",[467,1699,1700],{"class":469,"line":546},[467,1701,1702],{},"    ROWS BETWEEN 6 PRECEDING AND CURRENT ROW    -- 7 dòng gần nhất\n",[467,1704,1705],{"class":469,"line":552},[467,1706,791],{},[467,1708,1709],{"class":469,"line":558},[467,1710,543],{"emptyLinePlaceholder":542},[467,1712,1713],{"class":469,"line":564},[467,1714,1715],{},"-- RANGE: đếm theo giá trị của ORDER BY column\n",[467,1717,1718],{"class":469,"line":569},[467,1719,1687],{},[467,1721,1722],{"class":469,"line":575},[467,1723,1692],{},[467,1725,1726],{"class":469,"line":581},[467,1727,1697],{},[467,1729,1730],{"class":469,"line":587},[467,1731,1732],{},"    RANGE BETWEEN INTERVAL 7 DAY PRECEDING AND CURRENT ROW  -- 7 ngày gần nhất\n",[467,1734,1735],{"class":469,"line":826},[467,1736,791],{},[467,1738,1739],{"class":469,"line":832},[467,1740,543],{"emptyLinePlaceholder":542},[467,1742,1743],{"class":469,"line":838},[467,1744,1745],{},"-- GROUPS: đếm theo nhóm peer (các row có cùng giá trị ORDER BY)\n",[467,1747,1748],{"class":469,"line":843},[467,1749,1687],{},[467,1751,1752],{"class":469,"line":929},[467,1753,1692],{},[467,1755,1756],{"class":469,"line":934},[467,1757,1697],{},[467,1759,1760],{"class":469,"line":940},[467,1761,1762],{},"    GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW  -- nhóm hiện tại + 1 nhóm trước\n",[467,1764,1765],{"class":469,"line":1158},[467,1766,791],{},[1768,1769,1770,1786],"table",{},[1771,1772,1773],"thead",{},[1774,1775,1776,1780,1783],"tr",{},[1777,1778,1779],"th",{},"Frame Unit",[1777,1781,1782],{},"Đếm theo",[1777,1784,1785],{},"Dùng khi",[1787,1788,1789,1803,1816],"tbody",{},[1774,1790,1791,1797,1800],{},[1792,1793,1794],"td",{},[435,1795,1796],{},"ROWS",[1792,1798,1799],{},"Số dòng vật lý",[1792,1801,1802],{},"Dữ liệu dày, mỗi dòng là 1 record",[1774,1804,1805,1810,1813],{},[1792,1806,1807],{},[435,1808,1809],{},"RANGE",[1792,1811,1812],{},"Giá trị của ORDER BY",[1792,1814,1815],{},"Dữ liệu thưa, cần khoảng thời gian thực",[1774,1817,1818,1823,1826],{},[1792,1819,1820],{},[435,1821,1822],{},"GROUPS",[1792,1824,1825],{},"Nhóm peer (cùng giá trị)",[1792,1827,1828],{},"Cần aggregate theo nhóm logic",[487,1830,1832],{"id":1831},"top-n-per-group-idiom-kinh-điển","Top-N per group (idiom kinh điển)",[458,1834,1836],{"className":460,"code":1835,"language":462,"meta":463,"style":463},"WITH ranked AS (\n    SELECT *,\n        ROW_NUMBER() OVER (\n            PARTITION BY user_id ORDER BY created_at DESC\n        ) AS rn,\n        RANK() OVER (\n            PARTITION BY user_id ORDER BY total DESC\n        ) AS rank_by_value\n    FROM orders\n)\nSELECT * FROM ranked\nWHERE rn \u003C= 3;       -- 3 đơn gần nhất mỗi user\n\n-- RANK vs DENSE_RANK vs ROW_NUMBER:\n-- VALUES:    100, 100,  90,  80,  80\n-- RANK:        1,   1,   3,   4,   4   ← bỏ gap\n-- DENSE_RANK:  1,   1,   2,   3,   3   ← không bỏ gap\n-- ROW_NUMBER:  1,   2,   3,   4,   5   ← unique\n",[435,1837,1838,1842,1847,1852,1857,1862,1867,1872,1877,1881,1885,1890,1895,1899,1904,1909,1914,1919],{"__ignoreMap":463},[467,1839,1840],{"class":469,"line":470},[467,1841,777],{},[467,1843,1844],{"class":469,"line":476},[467,1845,1846],{},"    SELECT *,\n",[467,1848,1849],{"class":469,"line":482},[467,1850,1851],{},"        ROW_NUMBER() OVER (\n",[467,1853,1854],{"class":469,"line":539},[467,1855,1856],{},"            PARTITION BY user_id ORDER BY created_at DESC\n",[467,1858,1859],{"class":469,"line":546},[467,1860,1861],{},"        ) AS rn,\n",[467,1863,1864],{"class":469,"line":552},[467,1865,1866],{},"        RANK() OVER (\n",[467,1868,1869],{"class":469,"line":558},[467,1870,1871],{},"            PARTITION BY user_id ORDER BY total DESC\n",[467,1873,1874],{"class":469,"line":564},[467,1875,1876],{},"        ) AS rank_by_value\n",[467,1878,1879],{"class":469,"line":569},[467,1880,639],{},[467,1882,1883],{"class":469,"line":575},[467,1884,791],{},[467,1886,1887],{"class":469,"line":581},[467,1888,1889],{},"SELECT * FROM ranked\n",[467,1891,1892],{"class":469,"line":587},[467,1893,1894],{},"WHERE rn \u003C= 3;       -- 3 đơn gần nhất mỗi user\n",[467,1896,1897],{"class":469,"line":826},[467,1898,543],{"emptyLinePlaceholder":542},[467,1900,1901],{"class":469,"line":832},[467,1902,1903],{},"-- RANK vs DENSE_RANK vs ROW_NUMBER:\n",[467,1905,1906],{"class":469,"line":838},[467,1907,1908],{},"-- VALUES:    100, 100,  90,  80,  80\n",[467,1910,1911],{"class":469,"line":843},[467,1912,1913],{},"-- RANK:        1,   1,   3,   4,   4   ← bỏ gap\n",[467,1915,1916],{"class":469,"line":929},[467,1917,1918],{},"-- DENSE_RANK:  1,   1,   2,   3,   3   ← không bỏ gap\n",[467,1920,1921],{"class":469,"line":934},[467,1922,1923],{},"-- ROW_NUMBER:  1,   2,   3,   4,   5   ← unique\n",[487,1925,1927],{"id":1926},"running-total-moving-average","Running total & Moving Average",[458,1929,1931],{"className":460,"code":1930,"language":462,"meta":463,"style":463},"SELECT\n    order_date,\n    total,\n    -- Running total: tổng lũy kế\n    SUM(total) OVER (ORDER BY order_date) AS running_total,\n\n    -- Moving average 7 dòng (ROWS)\n    AVG(total) OVER (\n        ORDER BY order_date\n        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW\n    ) AS ma7_rows,\n\n    -- Moving average 7 ngày thực (RANGE)\n    AVG(total) OVER (\n        ORDER BY order_date\n        RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW\n    ) AS ma7_range\nFROM orders;\n",[435,1932,1933,1938,1943,1948,1953,1958,1962,1967,1972,1977,1982,1987,1991,1996,2000,2004,2009,2014],{"__ignoreMap":463},[467,1934,1935],{"class":469,"line":470},[467,1936,1937],{},"SELECT\n",[467,1939,1940],{"class":469,"line":476},[467,1941,1942],{},"    order_date,\n",[467,1944,1945],{"class":469,"line":482},[467,1946,1947],{},"    total,\n",[467,1949,1950],{"class":469,"line":539},[467,1951,1952],{},"    -- Running total: tổng lũy kế\n",[467,1954,1955],{"class":469,"line":546},[467,1956,1957],{},"    SUM(total) OVER (ORDER BY order_date) AS running_total,\n",[467,1959,1960],{"class":469,"line":552},[467,1961,543],{"emptyLinePlaceholder":542},[467,1963,1964],{"class":469,"line":558},[467,1965,1966],{},"    -- Moving average 7 dòng (ROWS)\n",[467,1968,1969],{"class":469,"line":564},[467,1970,1971],{},"    AVG(total) OVER (\n",[467,1973,1974],{"class":469,"line":569},[467,1975,1976],{},"        ORDER BY order_date\n",[467,1978,1979],{"class":469,"line":575},[467,1980,1981],{},"        ROWS BETWEEN 6 PRECEDING AND CURRENT ROW\n",[467,1983,1984],{"class":469,"line":581},[467,1985,1986],{},"    ) AS ma7_rows,\n",[467,1988,1989],{"class":469,"line":587},[467,1990,543],{"emptyLinePlaceholder":542},[467,1992,1993],{"class":469,"line":826},[467,1994,1995],{},"    -- Moving average 7 ngày thực (RANGE)\n",[467,1997,1998],{"class":469,"line":832},[467,1999,1971],{},[467,2001,2002],{"class":469,"line":838},[467,2003,1976],{},[467,2005,2006],{"class":469,"line":843},[467,2007,2008],{},"        RANGE BETWEEN INTERVAL 6 DAY PRECEDING AND CURRENT ROW\n",[467,2010,2011],{"class":469,"line":929},[467,2012,2013],{},"    ) AS ma7_range\n",[467,2015,2016],{"class":469,"line":934},[467,2017,2018],{},"FROM orders;\n",[487,2020,2022],{"id":2021},"so-sánh-period-over-period-lag-lead","So sánh period-over-period (LAG \u002F LEAD)",[458,2024,2026],{"className":460,"code":2025,"language":462,"meta":463,"style":463},"SELECT\n    DATE_FORMAT(created_at, '%Y-%m') AS month,\n    SUM(total) AS revenue,\n    LAG(SUM(total)) OVER (\n        ORDER BY DATE_FORMAT(created_at, '%Y-%m')\n    ) AS prev_month,\n    LEAD(SUM(total)) OVER (\n        ORDER BY DATE_FORMAT(created_at, '%Y-%m')\n    ) AS next_month,\n    ROUND(\n        (SUM(total) - LAG(SUM(total)) OVER (\n            ORDER BY DATE_FORMAT(created_at, '%Y-%m')\n        ))\n        \u002F LAG(SUM(total)) OVER (\n            ORDER BY DATE_FORMAT(created_at, '%Y-%m')\n        ) * 100,\n        2\n    ) AS mom_growth_pct\nFROM orders\nGROUP BY DATE_FORMAT(created_at, '%Y-%m');\n",[435,2027,2028,2032,2037,2042,2047,2052,2057,2062,2066,2071,2076,2081,2086,2091,2096,2100,2105,2110,2115,2120],{"__ignoreMap":463},[467,2029,2030],{"class":469,"line":470},[467,2031,1937],{},[467,2033,2034],{"class":469,"line":476},[467,2035,2036],{},"    DATE_FORMAT(created_at, '%Y-%m') AS month,\n",[467,2038,2039],{"class":469,"line":482},[467,2040,2041],{},"    SUM(total) AS revenue,\n",[467,2043,2044],{"class":469,"line":539},[467,2045,2046],{},"    LAG(SUM(total)) OVER (\n",[467,2048,2049],{"class":469,"line":546},[467,2050,2051],{},"        ORDER BY DATE_FORMAT(created_at, '%Y-%m')\n",[467,2053,2054],{"class":469,"line":552},[467,2055,2056],{},"    ) AS prev_month,\n",[467,2058,2059],{"class":469,"line":558},[467,2060,2061],{},"    LEAD(SUM(total)) OVER (\n",[467,2063,2064],{"class":469,"line":564},[467,2065,2051],{},[467,2067,2068],{"class":469,"line":569},[467,2069,2070],{},"    ) AS next_month,\n",[467,2072,2073],{"class":469,"line":575},[467,2074,2075],{},"    ROUND(\n",[467,2077,2078],{"class":469,"line":581},[467,2079,2080],{},"        (SUM(total) - LAG(SUM(total)) OVER (\n",[467,2082,2083],{"class":469,"line":587},[467,2084,2085],{},"            ORDER BY DATE_FORMAT(created_at, '%Y-%m')\n",[467,2087,2088],{"class":469,"line":826},[467,2089,2090],{},"        ))\n",[467,2092,2093],{"class":469,"line":832},[467,2094,2095],{},"        \u002F LAG(SUM(total)) OVER (\n",[467,2097,2098],{"class":469,"line":838},[467,2099,2085],{},[467,2101,2102],{"class":469,"line":843},[467,2103,2104],{},"        ) * 100,\n",[467,2106,2107],{"class":469,"line":929},[467,2108,2109],{},"        2\n",[467,2111,2112],{"class":469,"line":934},[467,2113,2114],{},"    ) AS mom_growth_pct\n",[467,2116,2117],{"class":469,"line":940},[467,2118,2119],{},"FROM orders\n",[467,2121,2122],{"class":469,"line":1158},[467,2123,2124],{},"GROUP BY DATE_FORMAT(created_at, '%Y-%m');\n",[487,2126,2128],{"id":2127},"first_value-last_value-nth_value","FIRST_VALUE \u002F LAST_VALUE \u002F NTH_VALUE",[458,2130,2132],{"className":460,"code":2131,"language":462,"meta":463,"style":463},"SELECT\n    user_id, order_date, total,\n    FIRST_VALUE(total) OVER (\n        PARTITION BY user_id ORDER BY order_date\n        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING\n    ) AS first_order_value,\n    NTH_VALUE(total, 2) OVER (\n        PARTITION BY user_id ORDER BY order_date\n        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING\n    ) AS second_order_value\nFROM orders;\n",[435,2133,2134,2138,2143,2148,2153,2158,2163,2168,2172,2176,2181],{"__ignoreMap":463},[467,2135,2136],{"class":469,"line":470},[467,2137,1937],{},[467,2139,2140],{"class":469,"line":476},[467,2141,2142],{},"    user_id, order_date, total,\n",[467,2144,2145],{"class":469,"line":482},[467,2146,2147],{},"    FIRST_VALUE(total) OVER (\n",[467,2149,2150],{"class":469,"line":539},[467,2151,2152],{},"        PARTITION BY user_id ORDER BY order_date\n",[467,2154,2155],{"class":469,"line":546},[467,2156,2157],{},"        ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING\n",[467,2159,2160],{"class":469,"line":552},[467,2161,2162],{},"    ) AS first_order_value,\n",[467,2164,2165],{"class":469,"line":558},[467,2166,2167],{},"    NTH_VALUE(total, 2) OVER (\n",[467,2169,2170],{"class":469,"line":564},[467,2171,2152],{},[467,2173,2174],{"class":469,"line":569},[467,2175,2157],{},[467,2177,2178],{"class":469,"line":575},[467,2179,2180],{},"    ) AS second_order_value\n",[467,2182,2183],{"class":469,"line":581},[467,2184,2018],{},[592,2186,2187,2192,2193,2196,2197,2200],{"color":594,"icon":595},[450,2188,2189,2191],{},[435,2190,1638],{}," thường không hoạt động như mong đợi"," với default frame (",[435,2194,2195],{},"RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW",") — nó luôn trả về current row. Phải explicit ",[435,2198,2199],{},"ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING"," để lấy giá trị cuối cùng của partition.",[487,2202,2204],{"id":2203},"percent_rank-cume_dist","PERCENT_RANK & CUME_DIST",[458,2206,2208],{"className":460,"code":2207,"language":462,"meta":463,"style":463},"SELECT\n    name, score,\n    ROUND(PERCENT_RANK() OVER (ORDER BY score DESC) * 100, 1) AS percentile,\n    ROUND(CUME_DIST() OVER (ORDER BY score DESC) * 100, 1) AS cumulative_pct\nFROM exam_results;\n",[435,2209,2210,2214,2219,2224,2229],{"__ignoreMap":463},[467,2211,2212],{"class":469,"line":470},[467,2213,1937],{},[467,2215,2216],{"class":469,"line":476},[467,2217,2218],{},"    name, score,\n",[467,2220,2221],{"class":469,"line":482},[467,2222,2223],{},"    ROUND(PERCENT_RANK() OVER (ORDER BY score DESC) * 100, 1) AS percentile,\n",[467,2225,2226],{"class":469,"line":539},[467,2227,2228],{},"    ROUND(CUME_DIST() OVER (ORDER BY score DESC) * 100, 1) AS cumulative_pct\n",[467,2230,2231],{"class":469,"line":546},[467,2232,2233],{},"FROM exam_results;\n",[592,2235,2236,2243],{"color":729,"icon":730},[432,2237,733,2238,737,2240],{},[450,2239,736],{},[739,2241,2242],{},"\"Trước 8.0 MySQL không có window function — làm sao tính top N per group?\"",[743,2244,2245],{},[432,2246,2247,2248,2251,2252],{},"Trick cũ dùng user variable: ",[435,2249,2250],{},"SET @rn := IF(@last_user = user_id, @rn+1, 1)",". Xấu xí, dễ bug. ",[450,2253,2254],{},"Khuyến nghị: upgrade 8.0+ ngay nếu còn đang stuck 5.7.",[427,2256,2258],{"id":2257},"_7-regular-expressions","7. Regular Expressions",[432,2260,2261],{},"MySQL hỗ trợ regex đầy đủ với nhiều function từ 8.0+.",[487,2263,2265],{"id":2264},"regexp-rlike-kiểm-tra-khớp-mẫu","REGEXP \u002F RLIKE — kiểm tra khớp mẫu",[458,2267,2269],{"className":460,"code":2268,"language":462,"meta":463,"style":463},"-- Tìm email Gmail\nSELECT email FROM users\nWHERE email REGEXP '^[a-zA-Z0-9._%+-]+@gmail\\\\.com$';\n\n-- RLIKE là alias của REGEXP\nSELECT * FROM products\nWHERE name RLIKE '^(iPhone|iPad|Mac)';\n\n-- Case-insensitive (mặc định)\nSELECT * FROM users WHERE name REGEXP '^nguyen';\n",[435,2270,2271,2276,2281,2286,2290,2295,2300,2305,2309,2314],{"__ignoreMap":463},[467,2272,2273],{"class":469,"line":470},[467,2274,2275],{},"-- Tìm email Gmail\n",[467,2277,2278],{"class":469,"line":476},[467,2279,2280],{},"SELECT email FROM users\n",[467,2282,2283],{"class":469,"line":482},[467,2284,2285],{},"WHERE email REGEXP '^[a-zA-Z0-9._%+-]+@gmail\\\\.com$';\n",[467,2287,2288],{"class":469,"line":539},[467,2289,543],{"emptyLinePlaceholder":542},[467,2291,2292],{"class":469,"line":546},[467,2293,2294],{},"-- RLIKE là alias của REGEXP\n",[467,2296,2297],{"class":469,"line":552},[467,2298,2299],{},"SELECT * FROM products\n",[467,2301,2302],{"class":469,"line":558},[467,2303,2304],{},"WHERE name RLIKE '^(iPhone|iPad|Mac)';\n",[467,2306,2307],{"class":469,"line":564},[467,2308,543],{"emptyLinePlaceholder":542},[467,2310,2311],{"class":469,"line":569},[467,2312,2313],{},"-- Case-insensitive (mặc định)\n",[467,2315,2316],{"class":469,"line":575},[467,2317,2318],{},"SELECT * FROM users WHERE name REGEXP '^nguyen';\n",[487,2320,2322],{"id":2321},"regexp_replace-thay-thế-theo-mẫu","REGEXP_REPLACE — thay thế theo mẫu",[458,2324,2326],{"className":460,"code":2325,"language":462,"meta":463,"style":463},"-- Chuẩn hóa số điện thoại: xóa tất cả ký tự không phải số\nSELECT REGEXP_REPLACE(phone, '[^0-9]', '') AS clean_phone\nFROM contacts;\n\n-- Mask email: giữ ký tự đầu và domain, ẩn phần giữa\nSELECT REGEXP_REPLACE(email, '(.).*(@.*)', '$1***$2') AS masked_email\nFROM users;\n",[435,2327,2328,2333,2338,2343,2347,2352,2357],{"__ignoreMap":463},[467,2329,2330],{"class":469,"line":470},[467,2331,2332],{},"-- Chuẩn hóa số điện thoại: xóa tất cả ký tự không phải số\n",[467,2334,2335],{"class":469,"line":476},[467,2336,2337],{},"SELECT REGEXP_REPLACE(phone, '[^0-9]', '') AS clean_phone\n",[467,2339,2340],{"class":469,"line":482},[467,2341,2342],{},"FROM contacts;\n",[467,2344,2345],{"class":469,"line":539},[467,2346,543],{"emptyLinePlaceholder":542},[467,2348,2349],{"class":469,"line":546},[467,2350,2351],{},"-- Mask email: giữ ký tự đầu và domain, ẩn phần giữa\n",[467,2353,2354],{"class":469,"line":552},[467,2355,2356],{},"SELECT REGEXP_REPLACE(email, '(.).*(@.*)', '$1***$2') AS masked_email\n",[467,2358,2359],{"class":469,"line":558},[467,2360,2361],{},"FROM users;\n",[487,2363,2365],{"id":2364},"regexp_substr-trích-xuất-chuỗi-con","REGEXP_SUBSTR — trích xuất chuỗi con",[458,2367,2369],{"className":460,"code":2368,"language":462,"meta":463,"style":463},"-- Trích xuất domain từ email\nSELECT email,\n       REGEXP_SUBSTR(email, '@(.+)$') AS domain\nFROM users;\n\n-- Trích xuất mã bưu điện từ địa chỉ\nSELECT address,\n       REGEXP_SUBSTR(address, '[0-9]{5,6}') AS postal_code\nFROM shipping_addresses;\n",[435,2370,2371,2376,2381,2386,2390,2394,2399,2404,2409],{"__ignoreMap":463},[467,2372,2373],{"class":469,"line":470},[467,2374,2375],{},"-- Trích xuất domain từ email\n",[467,2377,2378],{"class":469,"line":476},[467,2379,2380],{},"SELECT email,\n",[467,2382,2383],{"class":469,"line":482},[467,2384,2385],{},"       REGEXP_SUBSTR(email, '@(.+)$') AS domain\n",[467,2387,2388],{"class":469,"line":539},[467,2389,2361],{},[467,2391,2392],{"class":469,"line":546},[467,2393,543],{"emptyLinePlaceholder":542},[467,2395,2396],{"class":469,"line":552},[467,2397,2398],{},"-- Trích xuất mã bưu điện từ địa chỉ\n",[467,2400,2401],{"class":469,"line":558},[467,2402,2403],{},"SELECT address,\n",[467,2405,2406],{"class":469,"line":564},[467,2407,2408],{},"       REGEXP_SUBSTR(address, '[0-9]{5,6}') AS postal_code\n",[467,2410,2411],{"class":469,"line":569},[467,2412,2413],{},"FROM shipping_addresses;\n",[487,2415,2417],{"id":2416},"regexp_instr-tìm-vị-trí-khớp","REGEXP_INSTR — tìm vị trí khớp",[458,2419,2421],{"className":460,"code":2420,"language":462,"meta":463,"style":463},"-- Vị trí bắt đầu của dãy số đầu tiên trong chuỗi\nSELECT REGEXP_INSTR('Product-12345-XYZ', '[0-9]+') AS number_start;\n-- → 9\n\n-- Vị trí kết thúc (dùng option thứ 6 = 1)\nSELECT REGEXP_INSTR('Product-12345-XYZ', '[0-9]+', 1, 1, 1) AS number_end;\n-- → 13\n",[435,2422,2423,2428,2433,2438,2442,2447,2452],{"__ignoreMap":463},[467,2424,2425],{"class":469,"line":470},[467,2426,2427],{},"-- Vị trí bắt đầu của dãy số đầu tiên trong chuỗi\n",[467,2429,2430],{"class":469,"line":476},[467,2431,2432],{},"SELECT REGEXP_INSTR('Product-12345-XYZ', '[0-9]+') AS number_start;\n",[467,2434,2435],{"class":469,"line":482},[467,2436,2437],{},"-- → 9\n",[467,2439,2440],{"class":469,"line":539},[467,2441,543],{"emptyLinePlaceholder":542},[467,2443,2444],{"class":469,"line":546},[467,2445,2446],{},"-- Vị trí kết thúc (dùng option thứ 6 = 1)\n",[467,2448,2449],{"class":469,"line":552},[467,2450,2451],{},"SELECT REGEXP_INSTR('Product-12345-XYZ', '[0-9]+', 1, 1, 1) AS number_end;\n",[467,2453,2454],{"class":469,"line":558},[467,2455,2456],{},"-- → 13\n",[592,2458,733,2459,2462,2463,2466,2467,2469,2470,2473],{"color":594,"icon":730},[450,2460,2461],{},"Performance tip:"," Regex chậm hơn ",[435,2464,2465],{},"LIKE"," và full-text search. Nếu pattern đơn giản, luôn dùng ",[435,2468,2465],{}," (có thể dùng index nếu không bắt đầu bằng ",[435,2471,2472],{},"%","). Chỉ dùng regex khi thực sự cần pattern phức tạp.",[592,2475,2476,2477,2480],{"color":594,"icon":595},"MySQL dùng ",[450,2478,2479],{},"ICU regex engine"," (International Components for Unicode) từ 8.0.4+, hỗ trợ Unicode đầy đủ. Trước đó dùng Henry Spencer implementation với một số hạn chế về Unicode.",[427,2482,2484],{"id":2483},"_8-json-query","8. JSON query",[487,2486,2488],{"id":2487},"access-json-data","Access JSON data",[458,2490,2492],{"className":460,"code":2491,"language":462,"meta":463,"style":463},"SELECT\n    payload->'$.user' AS user_json,              -- trả về JSON object (có quote)\n    payload->>'$.user.name' AS user_name,        -- trả về text (đã unquote)\n    JSON_EXTRACT(payload, '$.tags[0]') AS first_tag;\n",[435,2493,2494,2498,2503,2508],{"__ignoreMap":463},[467,2495,2496],{"class":469,"line":470},[467,2497,1937],{},[467,2499,2500],{"class":469,"line":476},[467,2501,2502],{},"    payload->'$.user' AS user_json,              -- trả về JSON object (có quote)\n",[467,2504,2505],{"class":469,"line":482},[467,2506,2507],{},"    payload->>'$.user.name' AS user_name,        -- trả về text (đã unquote)\n",[467,2509,2510],{"class":469,"line":539},[467,2511,2512],{},"    JSON_EXTRACT(payload, '$.tags[0]') AS first_tag;\n",[592,2514,2515,737,2525,2527,2528,2530,2531,2534,2535,2537],{"color":594,"icon":595},[450,2516,2517,2520,2521,2524],{},[435,2518,2519],{},"->"," vs ",[435,2522,2523],{},"->>",":",[435,2526,2519],{}," trả về JSON value (có quote), ",[435,2529,2523],{}," trả về text đã unquote — tương đương ",[435,2532,2533],{},"JSON_UNQUOTE(JSON_EXTRACT(...))",". Dùng ",[435,2536,2523],{}," khi cần so sánh hoặc hiển thị.",[487,2539,2541],{"id":2540},"search-trong-json","Search trong JSON",[458,2543,2545],{"className":460,"code":2544,"language":462,"meta":463,"style":463},"-- Kiểm tra array có chứa giá trị\nSELECT * FROM events\nWHERE JSON_CONTAINS(payload->'$.tags', '\"vue\"');\n\n-- Kiểm tra path có tồn tại\nSELECT * FROM events WHERE JSON_CONTAINS_PATH(payload, 'one', '$.user.id');\n\n-- Search text trong toàn bộ document\nSELECT * FROM events\nWHERE JSON_SEARCH(payload, 'all', '%vue%') IS NOT NULL;\n",[435,2546,2547,2552,2557,2562,2566,2571,2576,2580,2585,2589],{"__ignoreMap":463},[467,2548,2549],{"class":469,"line":470},[467,2550,2551],{},"-- Kiểm tra array có chứa giá trị\n",[467,2553,2554],{"class":469,"line":476},[467,2555,2556],{},"SELECT * FROM events\n",[467,2558,2559],{"class":469,"line":482},[467,2560,2561],{},"WHERE JSON_CONTAINS(payload->'$.tags', '\"vue\"');\n",[467,2563,2564],{"class":469,"line":539},[467,2565,543],{"emptyLinePlaceholder":542},[467,2567,2568],{"class":469,"line":546},[467,2569,2570],{},"-- Kiểm tra path có tồn tại\n",[467,2572,2573],{"class":469,"line":552},[467,2574,2575],{},"SELECT * FROM events WHERE JSON_CONTAINS_PATH(payload, 'one', '$.user.id');\n",[467,2577,2578],{"class":469,"line":558},[467,2579,543],{"emptyLinePlaceholder":542},[467,2581,2582],{"class":469,"line":564},[467,2583,2584],{},"-- Search text trong toàn bộ document\n",[467,2586,2587],{"class":469,"line":569},[467,2588,2556],{},[467,2590,2591],{"class":469,"line":575},[467,2592,2593],{},"WHERE JSON_SEARCH(payload, 'all', '%vue%') IS NOT NULL;\n",[487,2595,2597],{"id":2596},"json_table-chuyển-json-thành-bảng-quan-hệ-804","JSON_TABLE() — chuyển JSON thành bảng quan hệ (8.0.4+)",[432,2599,2600,2603],{},[435,2601,2602],{},"JSON_TABLE()"," là công cụ mạnh nhất để làm việc với JSON trong MySQL — biến JSON array thành rows quan hệ:",[458,2605,2607],{"className":460,"code":2606,"language":462,"meta":463,"style":463},"-- Cho JSON: {\"items\": [{\"name\": \"Áo thun\", \"qty\": 2}, {\"name\": \"Quần jean\", \"qty\": 1}]}\nSELECT jt.*\nFROM orders,\nJSON_TABLE(\n    payload,\n    '$.items[*]'\n    COLUMNS (\n        item_name VARCHAR(100) PATH '$.name',\n        quantity INT PATH '$.qty',\n        row_num FOR ORDINALITY\n    )\n) AS jt;\n",[435,2608,2609,2614,2619,2624,2629,2634,2639,2644,2649,2654,2659,2663],{"__ignoreMap":463},[467,2610,2611],{"class":469,"line":470},[467,2612,2613],{},"-- Cho JSON: {\"items\": [{\"name\": \"Áo thun\", \"qty\": 2}, {\"name\": \"Quần jean\", \"qty\": 1}]}\n",[467,2615,2616],{"class":469,"line":476},[467,2617,2618],{},"SELECT jt.*\n",[467,2620,2621],{"class":469,"line":482},[467,2622,2623],{},"FROM orders,\n",[467,2625,2626],{"class":469,"line":539},[467,2627,2628],{},"JSON_TABLE(\n",[467,2630,2631],{"class":469,"line":546},[467,2632,2633],{},"    payload,\n",[467,2635,2636],{"class":469,"line":552},[467,2637,2638],{},"    '$.items[*]'\n",[467,2640,2641],{"class":469,"line":558},[467,2642,2643],{},"    COLUMNS (\n",[467,2645,2646],{"class":469,"line":564},[467,2647,2648],{},"        item_name VARCHAR(100) PATH '$.name',\n",[467,2650,2651],{"class":469,"line":569},[467,2652,2653],{},"        quantity INT PATH '$.qty',\n",[467,2655,2656],{"class":469,"line":575},[467,2657,2658],{},"        row_num FOR ORDINALITY\n",[467,2660,2661],{"class":469,"line":581},[467,2662,1150],{},[467,2664,2665],{"class":469,"line":587},[467,2666,2667],{},") AS jt;\n",[458,2669,2671],{"className":460,"code":2670,"language":462,"meta":463,"style":463},"-- Nested JSON — lồng nhiều cấp với NESTED PATH\n-- Cho JSON: {\"categories\": [{\"cat\": \"Thời trang\", \"products\": [{\"name\": \"Áo\", \"price\": 200}]}]}\nSELECT jt.cat_name, jt.product_name, jt.price\nFROM orders,\nJSON_TABLE(payload, '$.categories[*]'\n    COLUMNS (\n        cat_name VARCHAR(50) PATH '$.cat',\n        NESTED PATH '$.products[*]' COLUMNS (\n            product_name VARCHAR(100) PATH '$.name',\n            price DECIMAL(10,2) PATH '$.price'\n        )\n    )\n) AS jt;\n",[435,2672,2673,2678,2683,2688,2692,2697,2701,2706,2711,2716,2721,2726,2730],{"__ignoreMap":463},[467,2674,2675],{"class":469,"line":470},[467,2676,2677],{},"-- Nested JSON — lồng nhiều cấp với NESTED PATH\n",[467,2679,2680],{"class":469,"line":476},[467,2681,2682],{},"-- Cho JSON: {\"categories\": [{\"cat\": \"Thời trang\", \"products\": [{\"name\": \"Áo\", \"price\": 200}]}]}\n",[467,2684,2685],{"class":469,"line":482},[467,2686,2687],{},"SELECT jt.cat_name, jt.product_name, jt.price\n",[467,2689,2690],{"class":469,"line":539},[467,2691,2623],{},[467,2693,2694],{"class":469,"line":546},[467,2695,2696],{},"JSON_TABLE(payload, '$.categories[*]'\n",[467,2698,2699],{"class":469,"line":552},[467,2700,2643],{},[467,2702,2703],{"class":469,"line":558},[467,2704,2705],{},"        cat_name VARCHAR(50) PATH '$.cat',\n",[467,2707,2708],{"class":469,"line":564},[467,2709,2710],{},"        NESTED PATH '$.products[*]' COLUMNS (\n",[467,2712,2713],{"class":469,"line":569},[467,2714,2715],{},"            product_name VARCHAR(100) PATH '$.name',\n",[467,2717,2718],{"class":469,"line":575},[467,2719,2720],{},"            price DECIMAL(10,2) PATH '$.price'\n",[467,2722,2723],{"class":469,"line":581},[467,2724,2725],{},"        )\n",[467,2727,2728],{"class":469,"line":587},[467,2729,1150],{},[467,2731,2732],{"class":469,"line":826},[467,2733,2667],{},[592,2735,2737,2738,1621],{"color":594,"icon":2736},"i-lucide-arrow-right","Chi tiết về JSON data type, index, và best practices: xem ",[2739,2740,2742],"a",{"href":2741},"\u002Ftu-hoc\u002Fdatabase\u002Fmysql\u002Fjson","JSON trong MySQL",[487,2744,2746],{"id":2745},"index-trên-json-path","Index trên JSON path",[458,2748,2750],{"className":460,"code":2749,"language":462,"meta":463,"style":463},"-- Cách 1: Generated column (mọi version hỗ trợ JSON)\nALTER TABLE events\n    ADD COLUMN event_type VARCHAR(50)\n        AS (payload->>'$.type') VIRTUAL,\n    ADD INDEX idx_type (event_type);\n\n-- Query dùng generated column → dùng index\nSELECT * FROM events WHERE event_type = 'click';\n\n-- Cách 2: Functional index (8.0.13+) — không cần thêm cột\nCREATE INDEX idx_event_type ON events ((CAST(payload->>'$.type' AS CHAR(50))));\n",[435,2751,2752,2757,2762,2767,2772,2777,2781,2786,2791,2795,2800],{"__ignoreMap":463},[467,2753,2754],{"class":469,"line":470},[467,2755,2756],{},"-- Cách 1: Generated column (mọi version hỗ trợ JSON)\n",[467,2758,2759],{"class":469,"line":476},[467,2760,2761],{},"ALTER TABLE events\n",[467,2763,2764],{"class":469,"line":482},[467,2765,2766],{},"    ADD COLUMN event_type VARCHAR(50)\n",[467,2768,2769],{"class":469,"line":539},[467,2770,2771],{},"        AS (payload->>'$.type') VIRTUAL,\n",[467,2773,2774],{"class":469,"line":546},[467,2775,2776],{},"    ADD INDEX idx_type (event_type);\n",[467,2778,2779],{"class":469,"line":552},[467,2780,543],{"emptyLinePlaceholder":542},[467,2782,2783],{"class":469,"line":558},[467,2784,2785],{},"-- Query dùng generated column → dùng index\n",[467,2787,2788],{"class":469,"line":564},[467,2789,2790],{},"SELECT * FROM events WHERE event_type = 'click';\n",[467,2792,2793],{"class":469,"line":569},[467,2794,543],{"emptyLinePlaceholder":542},[467,2796,2797],{"class":469,"line":575},[467,2798,2799],{},"-- Cách 2: Functional index (8.0.13+) — không cần thêm cột\n",[467,2801,2802],{"class":469,"line":581},[467,2803,2804],{},"CREATE INDEX idx_event_type ON events ((CAST(payload->>'$.type' AS CHAR(50))));\n",[427,2806,2808],{"id":2807},"_9-aggregate","9. Aggregate",[458,2810,2812],{"className":460,"code":2811,"language":462,"meta":463,"style":463},"-- GROUP BY chuẩn\nSELECT city, COUNT(*) cnt\nFROM users WHERE active = 1\nGROUP BY city\nHAVING cnt > 10\nORDER BY cnt DESC;\n\n-- GROUP BY chỉ cho phép cột trong GROUP BY hoặc aggregate\n-- (default ONLY_FULL_GROUP_BY mode từ 5.7+)\n-- ❌ SELECT id, name, COUNT(*) FROM users GROUP BY city  -- lỗi\n\n-- GROUPING SETS \u002F ROLLUP\nSELECT city, status, COUNT(*)\nFROM orders\nGROUP BY city, status WITH ROLLUP;     -- thêm row subtotal + grand total\n",[435,2813,2814,2819,2824,2829,2834,2839,2844,2848,2853,2858,2863,2867,2872,2877,2881],{"__ignoreMap":463},[467,2815,2816],{"class":469,"line":470},[467,2817,2818],{},"-- GROUP BY chuẩn\n",[467,2820,2821],{"class":469,"line":476},[467,2822,2823],{},"SELECT city, COUNT(*) cnt\n",[467,2825,2826],{"class":469,"line":482},[467,2827,2828],{},"FROM users WHERE active = 1\n",[467,2830,2831],{"class":469,"line":539},[467,2832,2833],{},"GROUP BY city\n",[467,2835,2836],{"class":469,"line":546},[467,2837,2838],{},"HAVING cnt > 10\n",[467,2840,2841],{"class":469,"line":552},[467,2842,2843],{},"ORDER BY cnt DESC;\n",[467,2845,2846],{"class":469,"line":558},[467,2847,543],{"emptyLinePlaceholder":542},[467,2849,2850],{"class":469,"line":564},[467,2851,2852],{},"-- GROUP BY chỉ cho phép cột trong GROUP BY hoặc aggregate\n",[467,2854,2855],{"class":469,"line":569},[467,2856,2857],{},"-- (default ONLY_FULL_GROUP_BY mode từ 5.7+)\n",[467,2859,2860],{"class":469,"line":575},[467,2861,2862],{},"-- ❌ SELECT id, name, COUNT(*) FROM users GROUP BY city  -- lỗi\n",[467,2864,2865],{"class":469,"line":581},[467,2866,543],{"emptyLinePlaceholder":542},[467,2868,2869],{"class":469,"line":587},[467,2870,2871],{},"-- GROUPING SETS \u002F ROLLUP\n",[467,2873,2874],{"class":469,"line":826},[467,2875,2876],{},"SELECT city, status, COUNT(*)\n",[467,2878,2879],{"class":469,"line":832},[467,2880,2119],{},[467,2882,2883],{"class":469,"line":838},[467,2884,2885],{},"GROUP BY city, status WITH ROLLUP;     -- thêm row subtotal + grand total\n",[592,2887,733,2888,2893,2894,2897],{"color":594,"icon":730},[450,2889,2890],{},[435,2891,2892],{},"ONLY_FULL_GROUP_BY"," SQL mode (default 5.7+) ép GROUP BY chuẩn ANSI. Trước đó MySQL cho ",[435,2895,2896],{},"SELECT id, name FROM ... GROUP BY city"," chạy nhưng trả id\u002Fname bất kỳ row trong group → bug ẩn.",[427,2899,2901],{"id":2900},"_10-transaction-innodb-locking","10. Transaction & InnoDB locking",[487,2903,2905],{"id":2904},"cú-pháp","Cú pháp",[458,2907,2909],{"className":460,"code":2908,"language":462,"meta":463,"style":463},"START TRANSACTION;\nUPDATE accounts SET balance = balance - 1000 WHERE id = 1;\nUPDATE accounts SET balance = balance + 1000 WHERE id = 2;\nCOMMIT;\n-- Hoặc ROLLBACK;\n\n-- Savepoint\nSTART TRANSACTION;\nINSERT ...;\nSAVEPOINT sp1;\nUPDATE ...;\nROLLBACK TO sp1;\nCOMMIT;\n",[435,2910,2911,2916,2921,2926,2931,2936,2940,2945,2949,2954,2959,2964,2969],{"__ignoreMap":463},[467,2912,2913],{"class":469,"line":470},[467,2914,2915],{},"START TRANSACTION;\n",[467,2917,2918],{"class":469,"line":476},[467,2919,2920],{},"UPDATE accounts SET balance = balance - 1000 WHERE id = 1;\n",[467,2922,2923],{"class":469,"line":482},[467,2924,2925],{},"UPDATE accounts SET balance = balance + 1000 WHERE id = 2;\n",[467,2927,2928],{"class":469,"line":539},[467,2929,2930],{},"COMMIT;\n",[467,2932,2933],{"class":469,"line":546},[467,2934,2935],{},"-- Hoặc ROLLBACK;\n",[467,2937,2938],{"class":469,"line":552},[467,2939,543],{"emptyLinePlaceholder":542},[467,2941,2942],{"class":469,"line":558},[467,2943,2944],{},"-- Savepoint\n",[467,2946,2947],{"class":469,"line":564},[467,2948,2915],{},[467,2950,2951],{"class":469,"line":569},[467,2952,2953],{},"INSERT ...;\n",[467,2955,2956],{"class":469,"line":575},[467,2957,2958],{},"SAVEPOINT sp1;\n",[467,2960,2961],{"class":469,"line":581},[467,2962,2963],{},"UPDATE ...;\n",[467,2965,2966],{"class":469,"line":587},[467,2967,2968],{},"ROLLBACK TO sp1;\n",[467,2970,2971],{"class":469,"line":826},[467,2972,2930],{},[487,2974,2976],{"id":2975},"auto-commit","Auto-commit",[458,2978,2980],{"className":460,"code":2979,"language":462,"meta":463,"style":463},"-- Mặc định MỖI statement = 1 transaction (auto-commit ON)\nSET AUTOCOMMIT = 0;\n-- Sau đó phải COMMIT\u002FROLLBACK explicit\n",[435,2981,2982,2987,2992],{"__ignoreMap":463},[467,2983,2984],{"class":469,"line":470},[467,2985,2986],{},"-- Mặc định MỖI statement = 1 transaction (auto-commit ON)\n",[467,2988,2989],{"class":469,"line":476},[467,2990,2991],{},"SET AUTOCOMMIT = 0;\n",[467,2993,2994],{"class":469,"line":482},[467,2995,2996],{},"-- Sau đó phải COMMIT\u002FROLLBACK explicit\n",[487,2998,3000],{"id":2999},"isolation-level-default-repeatable-read","Isolation level — default REPEATABLE READ",[592,3002,3003,3011],{"color":729,"icon":730},[432,3004,733,3005,737,3008],{},[450,3006,3007],{},"Câu PV cốt lõi:",[739,3009,3010],{},"\"MySQL default isolation là gì?\"",[743,3012,3013],{},[432,3014,3015,3016,3019],{},"\"",[450,3017,3018],{},"REPEATABLE READ"," — cao hơn SQL Server \u002F Postgres (cả 2 mặc định READ COMMITTED). MySQL chọn REPEATABLE READ vì lý do replication (statement-based binlog cần consistent read).\"",[458,3021,3023],{"className":460,"code":3022,"language":462,"meta":463,"style":463},"-- Set level\nSET TRANSACTION ISOLATION LEVEL READ COMMITTED;\n\n-- 4 level MySQL hỗ trợ\n-- READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE\n",[435,3024,3025,3030,3035,3039,3044],{"__ignoreMap":463},[467,3026,3027],{"class":469,"line":470},[467,3028,3029],{},"-- Set level\n",[467,3031,3032],{"class":469,"line":476},[467,3033,3034],{},"SET TRANSACTION ISOLATION LEVEL READ COMMITTED;\n",[467,3036,3037],{"class":469,"line":482},[467,3038,543],{"emptyLinePlaceholder":542},[467,3040,3041],{"class":469,"line":539},[467,3042,3043],{},"-- 4 level MySQL hỗ trợ\n",[467,3045,3046],{"class":469,"line":546},[467,3047,3048],{},"-- READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE\n",[487,3050,3052],{"id":3051},"gap-lock-và-next-key-lock-đặc-thù-innodb","Gap lock và Next-key lock (đặc thù InnoDB)",[458,3054,3056],{"className":460,"code":3055,"language":462,"meta":463,"style":463},"-- Trong REPEATABLE READ, InnoDB lock cả khoảng trống giữa các index value\n-- để chống phantom read\nSELECT * FROM orders WHERE id BETWEEN 10 AND 20 FOR UPDATE;\n-- Lock không chỉ row 10-20 mà cả \"gap\" giữa các row → INSERT vào khoảng này bị block\n",[435,3057,3058,3063,3068,3073],{"__ignoreMap":463},[467,3059,3060],{"class":469,"line":470},[467,3061,3062],{},"-- Trong REPEATABLE READ, InnoDB lock cả khoảng trống giữa các index value\n",[467,3064,3065],{"class":469,"line":476},[467,3066,3067],{},"-- để chống phantom read\n",[467,3069,3070],{"class":469,"line":482},[467,3071,3072],{},"SELECT * FROM orders WHERE id BETWEEN 10 AND 20 FOR UPDATE;\n",[467,3074,3075],{"class":469,"line":539},[467,3076,3077],{},"-- Lock không chỉ row 10-20 mà cả \"gap\" giữa các row → INSERT vào khoảng này bị block\n",[592,3079,3080,3088],{"color":729,"icon":730},[432,3081,733,3082,737,3085],{},[450,3083,3084],{},"Câu PV nâng cao:",[739,3086,3087],{},"\"Gap lock là gì?\"",[743,3089,3090],{},[432,3091,3092],{},"\"InnoDB ở REPEATABLE READ lock cả khoảng trống giữa các index value, ngăn INSERT phantom. Tránh phantom read mà không cần Serializable. Hiệu ứng phụ: dễ deadlock hơn — fresher cần biết để debug khi gặp.\"",[487,3094,3096],{"id":3095},"select-for-update-for-share","SELECT ... FOR UPDATE \u002F FOR SHARE",[458,3098,3100],{"className":460,"code":3099,"language":462,"meta":463,"style":463},"START TRANSACTION;\n\n-- Lock exclusive — chặn UPDATE và FOR UPDATE khác\nSELECT * FROM products WHERE id = 1 FOR UPDATE;\n\n-- Lock shared — cho phép FOR SHARE khác đọc, chặn UPDATE\nSELECT * FROM products WHERE id = 1 FOR SHARE;\n\nUPDATE products SET stock = stock - 1 WHERE id = 1;\nCOMMIT;\n",[435,3101,3102,3106,3110,3115,3120,3124,3129,3134,3138,3143],{"__ignoreMap":463},[467,3103,3104],{"class":469,"line":470},[467,3105,2915],{},[467,3107,3108],{"class":469,"line":476},[467,3109,543],{"emptyLinePlaceholder":542},[467,3111,3112],{"class":469,"line":482},[467,3113,3114],{},"-- Lock exclusive — chặn UPDATE và FOR UPDATE khác\n",[467,3116,3117],{"class":469,"line":539},[467,3118,3119],{},"SELECT * FROM products WHERE id = 1 FOR UPDATE;\n",[467,3121,3122],{"class":469,"line":546},[467,3123,543],{"emptyLinePlaceholder":542},[467,3125,3126],{"class":469,"line":552},[467,3127,3128],{},"-- Lock shared — cho phép FOR SHARE khác đọc, chặn UPDATE\n",[467,3130,3131],{"class":469,"line":558},[467,3132,3133],{},"SELECT * FROM products WHERE id = 1 FOR SHARE;\n",[467,3135,3136],{"class":469,"line":564},[467,3137,543],{"emptyLinePlaceholder":542},[467,3139,3140],{"class":469,"line":569},[467,3141,3142],{},"UPDATE products SET stock = stock - 1 WHERE id = 1;\n",[467,3144,3145],{"class":469,"line":575},[467,3146,2930],{},[487,3148,3150],{"id":3149},"deadlock","Deadlock",[458,3152,3154],{"className":460,"code":3153,"language":462,"meta":463,"style":463},"-- Xem deadlock gần nhất\nSHOW ENGINE INNODB STATUS;\n\n-- Bật log deadlock vào error log\nSET GLOBAL innodb_print_all_deadlocks = ON;\n",[435,3155,3156,3161,3166,3170,3175],{"__ignoreMap":463},[467,3157,3158],{"class":469,"line":470},[467,3159,3160],{},"-- Xem deadlock gần nhất\n",[467,3162,3163],{"class":469,"line":476},[467,3164,3165],{},"SHOW ENGINE INNODB STATUS;\n",[467,3167,3168],{"class":469,"line":482},[467,3169,543],{"emptyLinePlaceholder":542},[467,3171,3172],{"class":469,"line":539},[467,3173,3174],{},"-- Bật log deadlock vào error log\n",[467,3176,3177],{"class":469,"line":546},[467,3178,3179],{},"SET GLOBAL innodb_print_all_deadlocks = ON;\n",[432,3181,3182],{},"InnoDB tự detect và rollback 1 transaction. Tránh: lock cùng thứ tự, giữ transaction ngắn.",[427,3184,3186],{"id":3185},"_11-explain","11. EXPLAIN",[458,3188,3190],{"className":460,"code":3189,"language":462,"meta":463,"style":463},"EXPLAIN SELECT * FROM orders WHERE user_id = 1;\n\nEXPLAIN ANALYZE\nSELECT * FROM orders WHERE user_id = 1;   -- 8.0+, chạy thực và đo\n",[435,3191,3192,3197,3201,3206],{"__ignoreMap":463},[467,3193,3194],{"class":469,"line":470},[467,3195,3196],{},"EXPLAIN SELECT * FROM orders WHERE user_id = 1;\n",[467,3198,3199],{"class":469,"line":476},[467,3200,543],{"emptyLinePlaceholder":542},[467,3202,3203],{"class":469,"line":482},[467,3204,3205],{},"EXPLAIN ANALYZE\n",[467,3207,3208],{"class":469,"line":539},[467,3209,3210],{},"SELECT * FROM orders WHERE user_id = 1;   -- 8.0+, chạy thực và đo\n",[487,3212,3214],{"id":3213},"output-columns","Output columns",[1768,3216,3217,3227],{},[1771,3218,3219],{},[1774,3220,3221,3224],{},[1777,3222,3223],{},"Cột",[1777,3225,3226],{},"Ý nghĩa",[1787,3228,3229,3239,3249,3258,3271,3281,3291,3301,3311],{},[1774,3230,3231,3236],{},[1792,3232,3233],{},[435,3234,3235],{},"id",[1792,3237,3238],{},"ID của SELECT",[1774,3240,3241,3246],{},[1792,3242,3243],{},[435,3244,3245],{},"select_type",[1792,3247,3248],{},"SIMPLE \u002F SUBQUERY \u002F DERIVED \u002F PRIMARY",[1774,3250,3251,3255],{},[1792,3252,3253],{},[435,3254,1768],{},[1792,3256,3257],{},"Bảng",[1774,3259,3260,3265],{},[1792,3261,3262],{},[435,3263,3264],{},"type",[1792,3266,3267,3270],{},[450,3268,3269],{},"Access type"," — quan trọng nhất",[1774,3272,3273,3278],{},[1792,3274,3275],{},[435,3276,3277],{},"possible_keys",[1792,3279,3280],{},"Index có thể dùng",[1774,3282,3283,3288],{},[1792,3284,3285],{},[435,3286,3287],{},"key",[1792,3289,3290],{},"Index thực sự dùng",[1774,3292,3293,3298],{},[1792,3294,3295],{},[435,3296,3297],{},"key_len",[1792,3299,3300],{},"Số byte key dùng",[1774,3302,3303,3308],{},[1792,3304,3305],{},[435,3306,3307],{},"rows",[1792,3309,3310],{},"Estimate số row đọc",[1774,3312,3313,3318],{},[1792,3314,3315],{},[435,3316,3317],{},"Extra",[1792,3319,3320],{},"Using where \u002F Using index \u002F Using filesort …",[487,3322,3324],{"id":3323},"access-type-best-worst","Access type (best → worst)",[458,3326,3331],{"className":3327,"code":3329,"language":3330},[3328],"language-text","system   — bảng 1 row\nconst    — match constant 1 row (PK)\neq_ref   — JOIN unique key, 1 row mỗi outer\nref      — JOIN non-unique key\nrange    — index range\nindex    — full index scan\nALL      — full table scan ⚠️\n","text",[435,3332,3329],{"__ignoreMap":463},[592,3334,3335,3336,1621],{"color":594,"icon":2736},"Từ MySQL 9.7 Community, Hypergraph Optimizer (DPhyp) có thể tạo ra EXPLAIN plan hoàn toàn khác — join order và access path được tối ưu tốt hơn. Xem chi tiết: ",[2739,3337,3339],{"href":3338},"#12-hypergraph-optimizer-mysql-97-community-edition","Hypergraph Optimizer",[427,3341,3343],{"id":3342},"_12-hypergraph-optimizer-mysql-97-community-edition","12. Hypergraph Optimizer (MySQL 9.7 Community Edition)",[592,3345,733,3346,3349],{"color":729,"icon":730},[450,3347,3348],{},"Cột mốc quan trọng:"," MySQL 9.7 Community Edition chính thức mang Hypergraph Optimizer đến với tất cả người dùng — trước đây optimizer này chỉ có trong HeatWave (cloud). Đây là bước nhảy vọt về query optimization, đặc biệt cho các query JOIN nhiều bảng.",[487,3351,3353],{"id":3352},"hypergraph-optimizer-là-gì","Hypergraph Optimizer là gì?",[432,3355,3356,3357,3360],{},"Hypergraph Optimizer sử dụng thuật toán ",[450,3358,3359],{},"DPhyp (Dynamic Programming Hypergraph)"," để tìm join order tối ưu, thay cho optimizer truyền thống vốn dùng greedy search. Kết quả thực tế:",[969,3362,3363,3369,3379,3386],{},[972,3364,3365,3368],{},[450,3366,3367],{},"2–5x nhanh hơn"," cho JOIN-heavy queries (star schema, analytics, nhiều bảng)",[972,3370,3371,3374,3375,3378],{},[450,3372,3373],{},"Join order tốt hơn"," — DPhyp khám phá ",[450,3376,3377],{},"toàn bộ không gian join order"," thay vì greedy chọn từng bước",[972,3380,3381,3382,3385],{},"Đặc biệt hiệu quả với ",[450,3383,3384],{},"OLAP \u002F analytics queries"," trên star schema (fact + nhiều dimension)",[972,3387,3388,3391],{},[450,3389,3390],{},"Subquery optimization"," tốt hơn — correlated subquery được rewrite hiệu quả hơn",[487,3393,3395],{"id":3394},"cách-bật-hypergraph-optimizer","Cách bật Hypergraph Optimizer",[458,3397,3399],{"className":460,"code":3398,"language":462,"meta":463,"style":463},"-- Bật ở session level (chỉ ảnh hưởng connection hiện tại)\nSET SESSION optimizer_switch = 'hypergraph=on';\n\n-- Bật ở global level (áp dụng cho tất cả connection mới)\nSET GLOBAL optimizer_switch = 'hypergraph=on';\n\n-- Per-statement: dùng optimizer hint — không cần thay đổi setting\nSELECT \u002F*+ SET_VAR(optimizer_switch='hypergraph=on') *\u002F\n    c.name, SUM(o.total) AS revenue\nFROM customers c\nJOIN orders o ON o.customer_id = c.id\nJOIN order_items oi ON oi.order_id = o.id\nJOIN products p ON p.id = oi.product_id\nGROUP BY c.name\nORDER BY revenue DESC;\n",[435,3400,3401,3406,3411,3415,3420,3425,3429,3434,3439,3444,3449,3454,3459,3464,3469],{"__ignoreMap":463},[467,3402,3403],{"class":469,"line":470},[467,3404,3405],{},"-- Bật ở session level (chỉ ảnh hưởng connection hiện tại)\n",[467,3407,3408],{"class":469,"line":476},[467,3409,3410],{},"SET SESSION optimizer_switch = 'hypergraph=on';\n",[467,3412,3413],{"class":469,"line":482},[467,3414,543],{"emptyLinePlaceholder":542},[467,3416,3417],{"class":469,"line":539},[467,3418,3419],{},"-- Bật ở global level (áp dụng cho tất cả connection mới)\n",[467,3421,3422],{"class":469,"line":546},[467,3423,3424],{},"SET GLOBAL optimizer_switch = 'hypergraph=on';\n",[467,3426,3427],{"class":469,"line":552},[467,3428,543],{"emptyLinePlaceholder":542},[467,3430,3431],{"class":469,"line":558},[467,3432,3433],{},"-- Per-statement: dùng optimizer hint — không cần thay đổi setting\n",[467,3435,3436],{"class":469,"line":564},[467,3437,3438],{},"SELECT \u002F*+ SET_VAR(optimizer_switch='hypergraph=on') *\u002F\n",[467,3440,3441],{"class":469,"line":569},[467,3442,3443],{},"    c.name, SUM(o.total) AS revenue\n",[467,3445,3446],{"class":469,"line":575},[467,3447,3448],{},"FROM customers c\n",[467,3450,3451],{"class":469,"line":581},[467,3452,3453],{},"JOIN orders o ON o.customer_id = c.id\n",[467,3455,3456],{"class":469,"line":587},[467,3457,3458],{},"JOIN order_items oi ON oi.order_id = o.id\n",[467,3460,3461],{"class":469,"line":826},[467,3462,3463],{},"JOIN products p ON p.id = oi.product_id\n",[467,3465,3466],{"class":469,"line":832},[467,3467,3468],{},"GROUP BY c.name\n",[467,3470,3471],{"class":469,"line":838},[467,3472,3473],{},"ORDER BY revenue DESC;\n",[487,3475,3477],{"id":3476},"kiểm-tra-optimizer-đã-dùng","Kiểm tra optimizer đã dùng",[458,3479,3481],{"className":460,"code":3480,"language":462,"meta":463,"style":463},"-- Sau khi chạy query, kiểm tra optimizer nào đã được sử dụng\nSELECT @@last_optimizer_used;\n-- Kết quả: 'hypergraph' hoặc 'old'\n",[435,3482,3483,3488,3493],{"__ignoreMap":463},[467,3484,3485],{"class":469,"line":470},[467,3486,3487],{},"-- Sau khi chạy query, kiểm tra optimizer nào đã được sử dụng\n",[467,3489,3490],{"class":469,"line":476},[467,3491,3492],{},"SELECT @@last_optimizer_used;\n",[467,3494,3495],{"class":469,"line":482},[467,3496,3497],{},"-- Kết quả: 'hypergraph' hoặc 'old'\n",[487,3499,3501],{"id":3500},"nên-dùng-hypergraph-hay-old-optimizer","Nên dùng Hypergraph hay old optimizer?",[1768,3503,3504,3514],{},[1771,3505,3506],{},[1774,3507,3508,3511],{},[1777,3509,3510],{},"Tình huống",[1777,3512,3513],{},"Nên dùng",[1787,3515,3516,3526,3535,3544,3552],{},[1774,3517,3518,3521],{},[1792,3519,3520],{},"Query JOIN 3+ bảng",[1792,3522,3523],{},[450,3524,3525],{},"Hypergraph",[1774,3527,3528,3531],{},[1792,3529,3530],{},"Star schema (fact + dimension tables)",[1792,3532,3533],{},[450,3534,3525],{},[1774,3536,3537,3540],{},[1792,3538,3539],{},"Subquery phức tạp, correlated subquery",[1792,3541,3542],{},[450,3543,3525],{},[1774,3545,3546,3549],{},[1792,3547,3548],{},"OLTP query đơn giản (1-2 bảng, indexed tốt)",[1792,3550,3551],{},"Old (planning overhead thấp hơn)",[1774,3553,3554,3557],{},[1792,3555,3556],{},"Ứng dụng đã tối ưu index kỹ, query ổn định",[1792,3558,3559],{},"Test cả 2, chọn cái nhanh hơn",[487,3561,3563],{"id":3562},"lưu-ý-quan-trọng","Lưu ý quan trọng",[969,3565,3566,3572,3582,3588],{},[972,3567,3568,3571],{},[450,3569,3570],{},"Không thay thế index tốt"," — Hypergraph chỉ chọn join order tốt hơn, không bù đắp cho việc thiếu index. Full table scan vẫn là full table scan.",[972,3573,3574,3577,3578,3581],{},[450,3575,3576],{},"Vẫn cần EXPLAIN"," để verify plan — dùng ",[435,3579,3580],{},"EXPLAIN ANALYZE"," để xem thời gian thực tế",[972,3583,3584,3587],{},[450,3585,3586],{},"Test trước khi bật global"," — một số edge case có thể regression, luôn test trên staging trước",[972,3589,3590,3593],{},[450,3591,3592],{},"Planning time có thể tăng nhẹ"," — DPhyp explore nhiều plan hơn → planning lâu hơn, nhưng execution nhanh hơn nhiều → tổng thời gian giảm",[458,3595,3597],{"className":460,"code":3596,"language":462,"meta":463,"style":463},"-- Kiểm tra version MySQL\nSELECT VERSION();\n\n-- Xem trạng thái hypergraph trong optimizer_switch\nSHOW VARIABLES LIKE 'optimizer_switch';\n\n-- Force dùng old optimizer nếu cần (per-statement)\nSELECT \u002F*+ SET_VAR(optimizer_switch='hypergraph=off') *\u002F\n    * FROM orders WHERE user_id = 1;\n",[435,3598,3599,3604,3609,3613,3618,3623,3627,3632,3637],{"__ignoreMap":463},[467,3600,3601],{"class":469,"line":470},[467,3602,3603],{},"-- Kiểm tra version MySQL\n",[467,3605,3606],{"class":469,"line":476},[467,3607,3608],{},"SELECT VERSION();\n",[467,3610,3611],{"class":469,"line":482},[467,3612,543],{"emptyLinePlaceholder":542},[467,3614,3615],{"class":469,"line":539},[467,3616,3617],{},"-- Xem trạng thái hypergraph trong optimizer_switch\n",[467,3619,3620],{"class":469,"line":546},[467,3621,3622],{},"SHOW VARIABLES LIKE 'optimizer_switch';\n",[467,3624,3625],{"class":469,"line":552},[467,3626,543],{"emptyLinePlaceholder":542},[467,3628,3629],{"class":469,"line":558},[467,3630,3631],{},"-- Force dùng old optimizer nếu cần (per-statement)\n",[467,3633,3634],{"class":469,"line":564},[467,3635,3636],{},"SELECT \u002F*+ SET_VAR(optimizer_switch='hypergraph=off') *\u002F\n",[467,3638,3639],{"class":469,"line":569},[467,3640,3641],{},"    * FROM orders WHERE user_id = 1;\n",[592,3643,3644,3651],{"color":729,"icon":730},[432,3645,733,3646,737,3648],{},[450,3647,736],{},[739,3649,3650],{},"\"Hypergraph Optimizer trong MySQL 9.7 là gì? Khác gì optimizer cũ?\"",[743,3652,3653],{},[432,3654,3655,3656,3659,3660,3663],{},"\"Hypergraph Optimizer sử dụng thuật toán DPhyp thay vì greedy search để tìm join order tối ưu. Trước đây chỉ có trên HeatWave (cloud), từ 9.7 có trên Community Edition. Ưu điểm chính: khám phá toàn bộ không gian join order thay vì greedy từng bước → plan tốt hơn cho query nhiều JOIN. Đánh đổi: planning time cao hơn, nhưng execution nhanh hơn 2-5x với query phức tạp. Dùng ",[435,3657,3658],{},"SET SESSION optimizer_switch = 'hypergraph=on'"," để bật, kiểm tra bằng ",[435,3661,3662],{},"SELECT @@last_optimizer_used",".\"",[427,3665,3667],{"id":3666},"_13-index-trong-innodb","13. Index trong InnoDB",[969,3669,3670,3680],{},[972,3671,3672,3675,3676,3679],{},[450,3673,3674],{},"Primary key = Clustered index"," (như SQL Server). Bảng InnoDB ",[739,3677,3678],{},"luôn"," clustered theo PK.",[972,3681,3682,3685],{},[450,3683,3684],{},"Secondary index"," = non-clustered, leaf chứa PK value (không phải row pointer).",[458,3687,3689],{"className":460,"code":3688,"language":462,"meta":463,"style":463},"CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);\n\n-- Covering index\nCREATE INDEX idx_orders_cover ON orders(user_id, created_at, total, status);\n\n-- Functional index (8.0.13+)\nCREATE INDEX idx_lower_email ON users ((LOWER(email)));\n\n-- Descending index (8.0+)\nCREATE INDEX idx_orders_recent ON orders(created_at DESC);\n\n-- Drop\nDROP INDEX idx_orders_user_date ON orders;\n",[435,3690,3691,3696,3700,3705,3710,3714,3719,3724,3728,3733,3738,3742,3747],{"__ignoreMap":463},[467,3692,3693],{"class":469,"line":470},[467,3694,3695],{},"CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);\n",[467,3697,3698],{"class":469,"line":476},[467,3699,543],{"emptyLinePlaceholder":542},[467,3701,3702],{"class":469,"line":482},[467,3703,3704],{},"-- Covering index\n",[467,3706,3707],{"class":469,"line":539},[467,3708,3709],{},"CREATE INDEX idx_orders_cover ON orders(user_id, created_at, total, status);\n",[467,3711,3712],{"class":469,"line":546},[467,3713,543],{"emptyLinePlaceholder":542},[467,3715,3716],{"class":469,"line":552},[467,3717,3718],{},"-- Functional index (8.0.13+)\n",[467,3720,3721],{"class":469,"line":558},[467,3722,3723],{},"CREATE INDEX idx_lower_email ON users ((LOWER(email)));\n",[467,3725,3726],{"class":469,"line":564},[467,3727,543],{"emptyLinePlaceholder":542},[467,3729,3730],{"class":469,"line":569},[467,3731,3732],{},"-- Descending index (8.0+)\n",[467,3734,3735],{"class":469,"line":575},[467,3736,3737],{},"CREATE INDEX idx_orders_recent ON orders(created_at DESC);\n",[467,3739,3740],{"class":469,"line":581},[467,3741,543],{"emptyLinePlaceholder":542},[467,3743,3744],{"class":469,"line":587},[467,3745,3746],{},"-- Drop\n",[467,3748,3749],{"class":469,"line":826},[467,3750,3751],{},"DROP INDEX idx_orders_user_date ON orders;\n",[592,3753,3754,3757,3758,3764],{"color":594,"icon":595},[450,3755,3756],{},"Mọi secondary index trong InnoDB chứa PK ở leaf."," Vì sao? Để locate row qua clustered index. Hệ quả: PK càng nhỏ → mọi index càng nhỏ. → ",[450,3759,3760,3761],{},"PK nên là ",[435,3762,3763],{},"BIGINT AUTO_INCREMENT"," thay vì UUID\u002Fcomposite key dài.",[592,3766,3767,3768],{"color":594,"icon":2736},"Tiếp theo: ",[2739,3769,3770],{"href":238},"Đặc thù MySQL & Performance",[3772,3773,3774],"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":463,"searchDepth":476,"depth":476,"links":3776},[3777,3780,3781,3786,3789,3797,3805,3811,3817,3818,3826,3830,3837],{"id":429,"depth":476,"text":430,"children":3778},[3779],{"id":489,"depth":482,"text":490},{"id":508,"depth":476,"text":509},{"id":602,"depth":476,"text":603,"children":3782},[3783,3784,3785],{"id":606,"depth":482,"text":607},{"id":657,"depth":482,"text":658},{"id":754,"depth":482,"text":755},{"id":848,"depth":476,"text":849,"children":3787},[3788],{"id":966,"depth":482,"text":967},{"id":1013,"depth":476,"text":1014,"children":3790},[3791,3792,3793,3794,3795,3796],{"id":1017,"depth":482,"text":1018},{"id":1055,"depth":482,"text":1056},{"id":1177,"depth":482,"text":1178},{"id":1266,"depth":482,"text":1267},{"id":1371,"depth":482,"text":1372},{"id":1480,"depth":482,"text":1481},{"id":1591,"depth":476,"text":1592,"children":3798},[3799,3800,3801,3802,3803,3804],{"id":1668,"depth":482,"text":1669},{"id":1831,"depth":482,"text":1832},{"id":1926,"depth":482,"text":1927},{"id":2021,"depth":482,"text":2022},{"id":2127,"depth":482,"text":2128},{"id":2203,"depth":482,"text":2204},{"id":2257,"depth":476,"text":2258,"children":3806},[3807,3808,3809,3810],{"id":2264,"depth":482,"text":2265},{"id":2321,"depth":482,"text":2322},{"id":2364,"depth":482,"text":2365},{"id":2416,"depth":482,"text":2417},{"id":2483,"depth":476,"text":2484,"children":3812},[3813,3814,3815,3816],{"id":2487,"depth":482,"text":2488},{"id":2540,"depth":482,"text":2541},{"id":2596,"depth":482,"text":2597},{"id":2745,"depth":482,"text":2746},{"id":2807,"depth":476,"text":2808},{"id":2900,"depth":476,"text":2901,"children":3819},[3820,3821,3822,3823,3824,3825],{"id":2904,"depth":482,"text":2905},{"id":2975,"depth":482,"text":2976},{"id":2999,"depth":482,"text":3000},{"id":3051,"depth":482,"text":3052},{"id":3095,"depth":482,"text":3096},{"id":3149,"depth":482,"text":3150},{"id":3185,"depth":476,"text":3186,"children":3827},[3828,3829],{"id":3213,"depth":482,"text":3214},{"id":3323,"depth":482,"text":3324},{"id":3342,"depth":476,"text":3343,"children":3831},[3832,3833,3834,3835,3836],{"id":3352,"depth":482,"text":3353},{"id":3394,"depth":482,"text":3395},{"id":3476,"depth":482,"text":3477},{"id":3500,"depth":482,"text":3501},{"id":3562,"depth":482,"text":3563},{"id":3666,"depth":476,"text":3667},"JOIN, subquery, derived tables & LATERAL (8.0.14+), set operations, CTE recursive, window function (8.0+), regular expressions, JSON query, transaction, InnoDB locking, EXPLAIN, Hypergraph Optimizer (9.7), index.","md",null,{},{"title":183,"icon":186},{"title":422,"description":3838},"eh2m3IACiOHhkyK-aTVK8Ol3Yv_uaR_5zassNLTYVq4",[3846,3848],{"title":178,"path":232,"stem":233,"description":3847,"icon":181,"children":-1},"Kiểu dữ liệu, DDL, DML, UPSERT (ON DUPLICATE KEY), function — gốc MySQL 8.4 \u002F 9.x.",{"title":188,"path":238,"stem":239,"description":3849,"icon":191,"children":-1},"InnoDB internals, buffer pool, replication source\u002Freplica, partitioning, performance tuning cho MySQL 8.4\u002F9.x.",1783490366754]