快速入门:查询优化器助手(预览版)

GitHub Copilot 可以帮助开发人员,尤其是那些没有深入 T-SQL 专业知识的开发人员,在不需要master数据库内部结构知识的情况下优化查询和分析性能瓶颈。 它可以分解复杂的 SQL,解释执行计划,并建议索引策略或重构机会,使开发人员能够保持其应用正常运行和性能,同时专注于功能交付。

开始吧

确保已连接到数据库,并使用 MSSQL 扩展打开活动编辑器窗口。 通过此连接, @mssql 聊天参与者可以了解数据库环境的上下文,从而提供准确的上下文感知建议。 如果没有数据库连接,聊天参与者将没有架构或数据上下文来提供有意义的响应。

以下示例使用 AdventureWorksLT2022 示例数据库,可以从 Microsoft SQL Server 示例和社区项目 主页下载该数据库。

为了获得最佳结果,请调整表和架构名称以匹配自己的环境。

确保聊天包含 @mssql 前缀。 例如,键入 @mssql 后跟问题或提示。 这可确保聊天参与者了解你请求与 SQL 相关的帮助。

使用 GitHub Copilot 优化性能

GitHub Copilot 提供了多种方法,可帮助开发人员编写高性能、生产就绪的数据库代码,而无需深入了解查询优化或执行计划分析的专业知识。 无论是生成新功能还是调查性能问题,GitHub Copilot 都可以显示见解、建议优化并帮助重构查询,所有这些作都在 Visual Studio Code 中的现有工作流中。

下面是通过聊天参与者可以询问的常见用例和示例。

优化查询

使用 GitHub Copilot 识别 SQL 或 ORM 查询中的效率低下,并建议提高性能的方法。 从重写慢查询到推荐索引或避免使用笛卡尔联接等反模式,GitHub Copilot 有助于基于当前上下文应用 T-SQL 和 ORM 最佳做法。

  • 优化以下查询:
SELECT *
FROM SalesLT.SalesOrderHeader
WHERE OrderDate > '2023-01-01';
  • 建议对此查询进行索引改进:
SELECT ProductID
FROM SalesLT.SalesOrderDetail
WHERE Quantity > 100;
  • 重写此查询以避免笛卡尔联接。 确保新查询遵循 T-SQL 最佳做法:
SELECT * FROM Customers, Order;
  • 重写此 Prisma 查询以避免不必要的嵌套选择并提高可读性:
const orders = await prisma.salesOrderHeader.findMany({
  where: {
    orderDate: {
      gt: new Date('2023-01-01')
    }
  }
});

执行计划分析

执行计划提供 SQL 引擎如何处理查询的详细细分。 GitHub Copilot 可以帮助你解释执行计划,识别嵌套循环联接等瓶颈,并根据实际查询模式和索引策略建议改进。

可以使用以下查询作为示例,使用 MSSQL 扩展中的“估计/实际计划”选项生成执行计划:

SELECT soh1.SalesOrderID AS OrderA,
       soh2.SalesOrderID AS OrderB,
       soh1.TotalDue AS TotalA,
       soh2.TotalDue AS TotalB
FROM SalesLT.SalesOrderHeader AS soh1
CROSS JOIN SalesLT.SalesOrderHeader AS soh2
WHERE soh1.TotalDue < soh2.TotalDue
ORDER BY soh2.TotalDue DESC;

小窍门

确保尽可能多地包含上下文:通过从编辑器中选择查询并将sqlplan文件包括在GitHub Copilot聊天窗口中。

显示 Visual Studio Code 中的执行计划示例的屏幕截图。

  • 根据数据库专家共享的执行计划,以下查询使用嵌套循环联接,这会影响应用的性能。 你能用简单的术语来解释为什么会发生这种情况? 此外,建议优化策略,以提高查询的性能。

可以使用以下查询作为示例,使用 MSSQL 扩展中的“估计/实际计划”选项生成执行计划:

SELECT c1.CustomerID,
       c1.LastName,
       c2.CustomerID AS MatchingCustomerID,
       c2.LastName AS MatchingLastName
FROM SalesLT.Customer AS c1
     INNER JOIN SalesLT.Customer AS c2
         ON c1.LastName = c2.LastName
        AND c1.CustomerID <> c2.CustomerID
OPTION (LOOP JOIN);

小窍门

请通过从编辑器中选择查询,并在 GitHub Copilot 聊天窗口中包括sqlplan文件,确保尽可能多地包含上下文。

显示 Visual Studio Code 中嵌套循环连接的执行计划的屏幕截图。

  • 说明此查询的执行计划,该查询对 TotalDue 执行带有筛选器的联接:
SELECT c.CustomerID,
       c.FirstName,
       c.LastName,
       soh.SalesOrderID,
       soh.TotalDue
FROM SalesLT.Customer AS c
     INNER JOIN SalesLT.SalesOrderHeader AS soh
         ON c.CustomerID = soh.CustomerID
WHERE soh.TotalDue > 500;

查询重组

使用通用表表达式(CTE)重组查询可以提高可读性和可维护性,尤其是对于复杂的逻辑或嵌套子查询。 GitHub Copilot 可帮助重写现有查询以使用 CTE,同时保留意向并提高清晰度。

  • 使用通用表表达式(CTEs)重写此查询以提高清晰度:
SELECT *
FROM (SELECT ProductID,
             SUM(Quantity) AS TotalQuantity
      FROM Sales
      GROUP BY ProductID) AS SubQuery;
  • 使用 CTE(通用表表达式)重写以下查询以提高可读性和可维护性:
SELECT soh.CustomerID,
       COUNT(*) AS OrderCount
FROM SalesLT.SalesOrderHeader AS soh
WHERE soh.OrderDate > '2022-01-01'
GROUP BY soh.CustomerID
HAVING COUNT(*) > 5;
  • 使用 CTE 将此查询中的聚合逻辑与筛选器条件分开:
SELECT ProductID,
       AVG(UnitPrice) AS AvgPrice
FROM SalesLT.SalesOrderDetail
GROUP BY ProductID
HAVING AVG(UnitPrice) > 50;

Code-First 性能场景

使用实体框架、Prisma 或 Sequelize 等 ORM 时,如果未优化查询,性能可能会降低。 GitHub Copilot 可帮助检测和解决代码优先工作流中缺少索引、低效筛选和 N+1 问题等问题。

  • 在 Prisma 项目中,如何确保在 SalesOrderHeader 中过滤 OrderDate 的查询能够有效利用索引?
  • 使用 Entity Framework Core,如何分析和优化按订单总值检索前 10 个客户的 LINQ 查询?
  • 在 Sequelize 中,如何重构查询,以提取订单历史记录以及产品详细信息以最大程度地减少 N+1 查询问题?

反馈:查询优化器助手

为了帮助我们优化和改进 MSSQL 扩展的 GitHub Copilot,请使用以下 GitHub 问题模板提交反馈: GitHub Copilot 反馈

提交反馈时,请考虑包括:

  • 测试方案 - 告诉我们你关注哪些领域,例如架构创建、查询生成、安全性、本地化。
  • 效果良好 - 描述任何感觉流畅、有用或超出预期的体验。
  • 问题或漏洞 – 包括任何问题、不一致或令人困惑的行为。 屏幕截图或屏幕录制特别有用!
  • 改进建议 - 分享改进可用性、扩大覆盖范围或增强 GitHub Copilot 响应的想法。