视频

SQL:覆盖索引,仅获取所需内容

仅从数据库获取所需内容时可用的优化

概述

部分对象是指实体 bean 并未完全填充所有属性,而是仅填充/加载了部分属性。

部分属性从数据库JDBC网络性能的角度来看非常重要,Ebean 中的一切都旨在支持部分填充的 bean。查询语言、增强、持久化、事件适配器以及 Ebean 的所有内部组件都基于部分填充的 bean 是常态的前提。

仅索引查询

如果执行 SQL 查询,其中使用的所有列都包含在索引中,那么数据库就有能力仅使用索引返回查询结果,并专门避免读取与表关联的数据块。这有时被称为“覆盖索引”或“覆盖查询”。

选定的列数少 = 仅索引查询的机会
database.find(Customer.class)

// only fetch the customer id and name
// ... if there is an index covering id and name the database has the ability
// ... to avoid reading the customer table data blocks and instead resolve the
// ... query by only using the index (which can be much faster)
.select("name")

// predicates and order by covered by index
.where().name.istartsWith("rob")
.orderBy().name.asc()
.findList();

仅索引联接

类似于“仅索引查询”,对于联接,联接表上需要/使用的列可以通过索引完全解析。例如,联接客户表,仅需要客户姓名。类似地,联接产品表,仅需要产品名称。这些是数据库通常可以通过仅使用索引解析联接的示例,而无需实际读取/访问表数据块(通过仅读取索引块并避免读取表块来解析联接)。

联接表中选定的列数少 = 仅索引联接的机会
database.find(Order.class)
...
// only fetch the customer id and name
// ... if there is an index on the customer table that is covering the customer id and name
// ... the database has the ability to avoid reading the customer table data blocks and instead
// ... resolve the join part of this query from only the customer index (which is faster)
.fetch("customer", "name")
...
.findList();

数据库缓冲区

当数据库处理查询时,它会创建缓冲区以执行排序、联接等。当涉及更多列时,这些缓冲区会更大,因为有更多数据。如果您只能选择所需的列,那么这些缓冲区以及排序、联接等涉及的数据量就会减少。如果可以排除的列是大型 varchar 列,或者实体 bean 映射到具有大量列的表,则这一点更为重要。

选定的列越少 = 数据库用于处理排序/联接等的缓冲区越小

JDBC 缓冲区

JDBC 驱动程序还具有缓冲区,可通过网络传输 resultSet 数据。更多列意味着更大的 JDBC 缓冲区和 JDBC 驱动程序所需的更多内存。

选择的列越少 = JDBC 驱动程序使用的缓冲区越小

网络

获取中包含的列越多,通过网络传输的数据就越多。请注意,某些 JDBC 驱动程序确实具有类似列压缩的功能,以便在值重复时减少网络负载(因为重复值在 SQL resultSet 数据中非常常见)。

选择的列越少 = 通过网络传输的数据越少

选择/获取

使用 select()fetch(),Ebean 可以轻松控制在查询中要获取的内容。select() 用于定义根级别的特定属性以进行获取/加载,而 fetch() 用于定义其他所有级别的属性以进行获取/加载(并对急加载/延迟加载和加载批处理大小等进行额外控制)。

// control the lazy loading of customers ...
List<Order> list = Ebean.find(Order.class)
   // fetch just these properties for the Order
  .select("status,orderDate,shipDate")
  // fetch customer name only
  .fetch("customer","name")
  .fetch("customer.shippingAddress", "*")
  .fetch("details", "*")
  // fetch product name only
  .fetch("details.product", "name")
  .where().eq("status",Order.Status.NEW)
  .findList();

自动调优

自动调优将针对每个用例调整每个查询以获取最少的属性集

手动优化查询以仅获取所需内容可能需要一些工作,即使您这样做,您也经常会遇到这样的情况:单个查询(如“按 ID 查找订单”)用于多个用户用例,并且每个用例都使用对象图的不同部分。

自动调优是一项功能,它可以针对每个查询相对于调用堆栈分析对象图使用情况,并提供一个仅选择/获取给定调用堆栈所使用内容的查询 - 有效地提供了一种优化查询以仅获取应用程序使用内容的良好自动化方式。