Otimização de Consulta Utilizando Índices

Definir e utilizar índices adequadamente pode aprimorar significativamente o desempenho da consulta.

As consultas do WebSphere eXtreme Scale podem usar plug-ins HashIndex integrados para aumentar o desempenho de consultas. Os índices podem ser definidos em atributos entity ou object. O mecanismo de consulta usará automaticamente os índices definidos se a sua cláusula WHERE usar uma das seguintes cadeias:

  • Uma expressão de comparação com os seguintes operadores: =, <, >, <= ou >= (quaisquer expressões de comparação, exceto não iguais <>)
  • Uma expressão BETWEEN
  • Operandos das expressões são constantes ou termos simples

Requisitos

Os índices têm os seguintes requisitos quando usados pela Consulta:
  • Todos os índices devem usar o plug-in HashIndex integrado.
  • Todos os índices devem ser estaticamente definidos. Os índices dinâmicos não são suportados.
  • A anotação @Index pode ser usada para criar automaticamente plug-ins HashIndex estáticos.
  • Todos os índices de um único atributo devem ter o conjunto de propriedades RangeIndex configurado como true.
  • Todos os índices compostos devem ter o conjunto de propriedades RangeIndex configurado como false.
  • Todos os índices de associação (relacionamento) devem ter o conjunto de propriedades RangeIndex configurado como false.

Para obter informações sobre a configuração do HashIndex, consulte o Plug-ins para Indexar Dados.

Para obter informações sobre a indexação, consulte o Indexação.

Para obter uma maneira mais eficiente de procurar objetos armazenados em cache, consulte Usando um Índice Composto

Uso de Dicas para Escolher um Índice

Um índice pode ser manualmente selecionado usando o método setHint nas interfaces Query e ObjectQuery com a constante HINT_USEINDEX. Isto pode ser útil quando a otimização de uma consulta usar o melhor índice de desempenho.

Exemplos de consulta que usam índices de atributo

Os exemplos a seguir utilizam termos simples: e.empid, e.name, e.salary, d.name, d.budget e e.isManager. Os exemplos assumem que os índices são definidos sobre os campos name, salary e budget de um objeto entity ou value. O campo empid é uma chave primária e isManager não possui índice definido.

A consulta a seguir utiliza ambos os índices sobre o campos name e salary. Ela retorna todos os funcionários com nomes iguais ao valor do primeiro parâmetro ou um salário igual ao valor do segundo parâmetro:

SELECT e FROM EmpBean e where e.name=?1 or e.salary=?2

A consulta a seguir usa ambos índices sobre os campos de nome e orçamento. Ela retorna todos os departamentos nomeados 'DEV' com um orçamento que é maior que 2000.

SELECT d FROM DeptBean dwhere d.name='DEV' and d.budget>2000

A consulta a seguir retorna todos os funcionários com um salário maior do que 3000 e com um valor sinalizador isManager igual ao valor do parâmetro. A consulta utiliza o índice que é definido sobre o campo salary e executa filtragem adicional ao avaliar a expressão de comparação: e.isManager=?1.

SELECT e FROM EmpBean e where e.salary>3000 and e.isManager=?1

A consulta a seguir localiza todos os funcionários que ganham mais que o primeiro parâmetro ou que qualquer funcionário que é um gerente. Embora o campo salary tenha um índice definido, a consulta varre o índice integrado que é baseado em chaves primárias do campo EmpBean e avalia a expressão: e.salary>?1 ou e.isManager=TRUE.

SELECT e FROM EmpBean e WHERE e.salary>?1 or e.isManager=TRUE

A consulta a seguir retorna funcionários com um nome que contém a letra a. Embora o campo name tenha um índice definido, a consulta não utiliza o índice porque o campo name é utilizado na expressão LIKE.

SELECT e FROM EmpBean e WHERE e.name LIKE '%a%'

A consulta a seguir localiza todos os funcionários com um nome que não seja "Smith". Embora o campo name tenha um índice definido, a consulta não utiliza o índice porque a consulta utiliza o operador de comparação não iguais ( <> ).

SELECT e FROM EmpBean e where e.name<>'Smith'

A seguinte consulta localiza todos os departamentos com um orçamento menor do que o valor do parâmetro e com um salário superior a 3000. A consulta utiliza um índice para o salário, mas não utiliza um índice para o orçamento porque dept.budget não é um termo simples. Os objetos dept são derivados da coleta e. Não é necessário utilizar o índice de orçamento para consultar objetos dept.

SELECT dept from EmpBean e, in (e.dept) dept where e.salary>3000 and dept.budget<?

A consulta a seguir localiza todos os funcionários com um salário maior do que o salário dos funcionários que possuem o empid e 1, 2 e 3. O salário do índice não é utilizado porque a comparação envolve uma subconsulta. O empid é uma chave primária, entretanto, ele é utilizado para uma procura de índice exclusiva porque todas as chaves primárias possuem um índice integrado definido.

SELECT e FROM EmpBean e WHERE e.salary > ALL (SELECT e1.salary FROM EmpBean e1 WHERE e1.empid=1 or e1.empid =2 or e1.empid=99)

Para verificar se o índice está sendo utilizado pela consulta, é possível visualizar o Plano de Consulta. A seguir, está um plano de consulta de exemplo para a consulta anterior:

for q2 in EmpBean ObjectMap using INDEX SCAN
    filter ( q2.salary >ALL     temp collection defined as
       IteratorUnionIndex of

         for q3 in EmpBean ObjectMap using UNIQUE INDEX key=(1)
        )

         for q3 in EmpBean ObjectMap using UNIQUE INDEX key=(2)
        )

         for q3 in EmpBean ObjectMap using UNIQUE INDEX key=(99)
        )
       returning new Tuple( q3.salary )
   returning new Tuple( q2  )

for q2 in EmpBean ObjectMap using RANGE INDEX on salary with range(3000,)
     for q3 in  q2.dept
      filter ( q3.budget <  ?1 )
   returning new Tuple( q3  )

Atributos de Indexação

Os índices podem ser definidos sobre qualquer tipo de atributo único com os limitadores anteriormente definidos.

definição de índices de entidade usando @Index

Para definir um índice em uma entidade, simplesmente defina uma anotação:

Entidades usando anotações

 	@Entity
 	public class Employee {
 	@Id int empid;
 	@Index String name
 	@Index double salary
 	@ManyToOne Department dept;
}
@Entity
 	public class Department {
 	@Id int deptid;
 	@Index String name;
 	@Index double budget;
 	boolean isManager;
 	@OneToMany Collection<Employee> employees;
 	}

Com XML

Os índices também podem ser definidos usando XML:
 	Entidades sem anotações

 	public class Employee {
 	int empid;
 	String name
 	double salary
 	Department dept;
 	}
 	 
 	public class Department {
 	int deptid;
 	String name;
 	double budget;
 	boolean isManager;
 	Collection employees;
 	}
XML do ObjectGrid com índices de atributos

<?xml version="1.0" encoding="UTF-8"?>
 	<objectGridConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://ibm.com/ws/objectgrid/config ../objectGrid.xsd"
 	xmlns="http://ibm.com/ws/objectgrid/config">
 	<objectGrids>
 	<objectGrid name="DepartmentGrid" entityMetadataXMLFile="entity.xml>
 	<backingMap name="Employee" pluginCollectionRef="Emp"/>
 	<backingMap name="Department" pluginCollectionRef="Dept"/>
 	</objectGrid>
 	</objectGrids>
 	<backingMapPluginCollections>
 	<backingMapPluginCollection id="Emp">
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="Employee.name"/>
 	<property name="AttributeName" type="java.lang.String" value="name"/>
 	<property name="RangeIndex" type="boolean" value="true"
 	description="Ranges are must be set to true for attributes." />
 	</bean>
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="Employee.salary"/>
 	<property name="AttributeName" type="java.lang.String" value="salary"/>
 	<property name="RangeIndex" type="boolean" value="true"
 	description="Ranges are must be set to true for attributes." />
 	</bean>
 	</backingMapPluginCollection>
 	<backingMapPluginCollection id="Dept">
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="Department.name"/>
 	<property name="AttributeName" type="java.lang.String" value="name"/>
 	<property name="RangeIndex" type="boolean" value="true"
 	description="Ranges are must be set to true for attributes." />
 	</bean>
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="Department.budget"/>
 	<property name="AttributeName" type="java.lang.String" value="budget"/>
 	<property name="RangeIndex" type="boolean" value="true"
 	description="Ranges are must be set to true for attributes." />
 	</bean>
 	</backingMapPluginCollection>
 	</backingMapPluginCollections>
 	</objectGridConfig>
Entidade XML

<?xml version="1.0" encoding="UTF-8"?>
 	<entity-mappings xmlns="http://ibm.com/ws/projector/config/emd"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://ibm.com/ws/projector/config/emd ./emd.xsd">
 	 
 	<description>Department entities</description>
 	<entity class-name="acme.Employee" name="Employee" access="FIELD">
 	<attributes>
 	<id name="empid" />
 	<basic name="name" />
 	<basic name="salary" />
 	<many-to-one name="department"
 	target-entity="acme.Department"
 	fetch="EAGER">
 	<cascade><cascade-persist/></cascade>
 	</many-to-one>
 	</attributes>
 	</entity>
 	<entity class-name="acme.Department" name="Department" access="FIELD">
 	<attributes>
 	<id name="deptid" />
 	<basic name="name" />
 	<basic name="budget" />
 	<basic name="isManager" />
 	<one-to-many name="employees"
 	target-entity="acme.Employee"
 	fetch="LAZY" mapped-by="parentNode">
 	<cascade><cascade-persist/></cascade>
 	</one-to-many>
 	</attributes>
 	</entity>
 	</entity-mappings>

Definição de índices para não-entidades usando XML

Os índices para tipos de não-entidade são definidos em XML. Não há diferença quando a criação do MapIndexPlugin para mapas de entidade e mapas de não-entidade.

Java bean
public class Employee {
 	int empid;
 	String name
 	double salary
 	Department dept;

	public class Department {
 	int deptid;
 	String name;
 	double budget;
 	boolean isManager;
 	Collection employees;
 	}
XML do ObjectGrid com índices de atributos

<?xml version="1.0" encoding="UTF-8"?>
 	<objectGridConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://ibm.com/ws/objectgrid/config ../objectGrid.xsd"
 	xmlns="http://ibm.com/ws/objectgrid/config">
 	<objectGrids>
 	<objectGrid name="DepartmentGrid">
 	<backingMap name="Employee" pluginCollectionRef="Emp"/>
 	<backingMap name="Department" pluginCollectionRef="Dept"/>
 	<querySchema>
 	<mapSchemas>
 	<mapSchema mapName="Employee" valueClass="acme.Employee"
 	primaryKeyField="empid" />
 	<mapSchema mapName="Department" valueClass="acme.Department"
 	primaryKeyField="deptid" />
 	</mapSchemas>
 	<relationships>
 	<relationship source="acme.Employee"
 	target="acme.Department"
 	relationField="dept" invRelationField="employees" />
 	</relationships>
 	</querySchema>
 	</objectGrid>
 	</objectGrids>
 	<backingMapPluginCollections>
 	<backingMapPluginCollection id="Emp">
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="Employee.name"/>
 	<property name="AttributeName" type="java.lang.String" value="name"/>
 	<property name="RangeIndex" type="boolean" value="true"
 	description="Ranges are must be set to true for attributes." />
 	</bean>
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="Employee.salary"/>
 	<property name="AttributeName" type="java.lang.String" value="salary"/>
 	<property name="RangeIndex" type="boolean" value="true"
 	description="Ranges are must be set to true for attributes." />
 	</bean>
 	</backingMapPluginCollection>
 	<backingMapPluginCollection id="Dept">
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="Department.name"/>
 	<property name="AttributeName" type="java.lang.String" value="name"/>
 	<property name="RangeIndex" type="boolean" value="true"
 	description="Ranges are must be set to true for attributes." />
 	</bean>
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="Department.budget"/>
 	<property name="AttributeName" type="java.lang.String" value="budget"/>
 	<property name="RangeIndex" type="boolean" value="true"
 	description="Ranges are must be set to true for attributes." />
 	</bean>
 	</backingMapPluginCollection>
 	</backingMapPluginCollections>
 	</objectGridConfig>

Indexando Relacionamentos

O WebSphere eXtreme Scale armazena as chaves estrangeiras para entidades relacionadas dentro do objeto-pai. Para entidades, as chaves são armazenadas na tupla subjacente. Para objetos não-entidade, as chaves são explicitamente armazenadas no objeto-pai.

Incluir um índice em um atributo de relacionamento pode acelerar consultas que utilizam referências cíclicas ou utilizam os filtros de consulta IS NULL, IS EMPTY, SIZE e MEMBER OF. Ambas as associações únicas e com diversos valores podem ter a anotação @Index ou uma configuração de plug-in HashIndex em um arquivo XML descritor do ObjectGrid.

Definição de índices de relacionamento de entidade usando @Index

O exemplo a seguir define entidades com anotações @Index:

Entidade com anotação

@Entity
public class Node {
    @ManyToOne @Index
    Node parentNode;

    @OneToMany @Index
    List<Node> childrenNodes = new ArrayList();

    @OneToMany @Index
    List<BusinessUnitType> businessUnitTypes = new ArrayList();
}

Definição dos índices de relacionamento da entidade usando XML

O exemplo a seguir define as mesmas entidades e índices usando XML com plug-ins HashIndex:

 	Entidade sem anotações

 	public class Node {
 	int nodeId;
 	Node parentNode;
 	List<Node> childrenNodes = new ArrayList();
 	List<BusinessUnitType> businessUnitTypes = new ArrayList();
 	}
ObjectGrid XML

<?xml version="1.0" encoding="UTF-8"?>
 	<objectGridConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://ibm.com/ws/objectgrid/config ../objectGrid.xsd"
 	xmlns="http://ibm.com/ws/objectgrid/config">
 	<objectGrids>
 	<objectGrid name="ObjectGrid_Entity" entityMetadataXMLFile="entity.xml>
 	<backingMap name="Node" pluginCollectionRef="Node"/>
 	<backingMap name="BusinessUnitType" pluginCollectionRef="BusinessUnitType"/>
 	</objectGrid>
 	</objectGrids>
 	<backingMapPluginCollections>
 	<backingMapPluginCollection id="Node">
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="parentNode"/>
 	<property name="AttributeName" type="java.lang.String" value="parentNode"/>
<property name="RangeIndex" type="boolean" value="false"
 	description="Ranges are not supported for association indexes." /> 	</bean>
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="businessUnitType"/>
 	<property name="AttributeName" type="java.lang.String" value="businessUnitTypes"/>

<property name="RangeIndex" type="boolean" value="false"
 	description="Ranges are not supported for association indexes." />
	</bean>
 	<bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
 	<property name="Name" type="java.lang.String" value="childrenNodes"/>
 	<property name="AttributeName" type="java.lang.String" value="childrenNodes"/>
<property name="RangeIndex" type="boolean" value="false"
 	description="Ranges are not supported for association indexes." />
 	</bean>
 	</backingMapPluginCollection>
 	</backingMapPluginCollections>
 	</objectGridConfig>
 	 
 Entidade XML

 	<?xml version="1.0" encoding="UTF-8"?>
 	<entity-mappings xmlns="http://ibm.com/ws/projector/config/emd"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 	xsi:schemaLocation="http://ibm.com/ws/projector/config/emd ./emd.xsd">
 	 
 	<description>My entities</description>
 	<entity class-name="acme.Node" name="Account" access="FIELD">
 	<attributes>
 	<id name="nodeId" />
 	<one-to-many name="childrenNodes"
 	target-entity="acme.Node"
 	fetch="EAGER" mapped-by="parentNode">
 	<cascade><cascade-all/></cascade>
 	</one-to-many>
 	<many-to-one name="parentNodes"
 	target-entity="acme.Node"
 	fetch="LAZY" mapped-by="childrenNodes">
 	<cascade><cascade-none/></cascade>
 	</one-to-many>
 	<many-to-one name="businessUnitTypes"
 	target-entity="acme.BusinessUnitType"
 	fetch="EAGER">
 	<cascade><cascade-persist/></cascade>
 	</many-to-one>
</attributes>
 	</entity>
 	<entity class-name="acme.BusinessUnitType" name="BusinessUnitType" access="FIELD">
 	<attributes>
 	<id name="buId" />
 	<basic name="TypeDescription" />
 	</attributes>
 	</entity>
 	</entity-mappings>

Usando os índices anteriormente definidos, os exemplos de consulta de entidades a seguir são otimizados:

SELECT n FROM Node n WHERE n.parentNode is null
SELECT n FROM Node n WHERE n.businessUnitTypes is EMPTY
 	SELECT n FROM Node n WHERE size(n.businessUnitTypes)>=10
 	SELECT n FROM BusinessUnitType b, Node n WHERE b member of n.businessUnitTypes and b.name='TELECOM'

Definição dos índices de relacionamento de não-entidade

O exemplo a seguir define um plug-in HashIndex para mapas de não-entidade em um arquivo XML descritor do ObjectGrid:

<?xml version="1.0" encoding="UTF-8"?>
<objectGridConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://ibm.com/ws/objectgrid/config ../objectGrid.xsd"
  xmlns="http://ibm.com/ws/objectgrid/config">
  <objectGrids>
    <objectGrid name="ObjectGrid_POJO">
      <backingMap name="Node" pluginCollectionRef="Node"/>
      <backingMap name="BusinessUnitType" pluginCollectionRef="BusinessUnitType"/>
      <querySchema>
        <mapSchemas>
          <mapSchema mapName="Node" valueClass="com.ibm.websphere.objectgrid.samples.entity.Node"
            primaryKeyField="id" />
          <mapSchema mapName="BusinessUnitType"
            valueClass="com.ibm.websphere.objectgrid.samples.entity.BusinessUnitType"
            primaryKeyField="id" />
        </mapSchemas>
        <relationships>
          <relationship source="com.ibm.websphere.objectgrid.samples.entity.Node" 
            target="com.ibm.websphere.objectgrid.samples.entity.Node"
            relationField="parentNodeId" invRelationField="childrenNodeIds" />
          <relationship source="com.ibm.websphere.objectgrid.samples.entity.Node" 
            target="com.ibm.websphere.objectgrid.samples.entity.BusinessUnitType"
            relationField="businessUnitTypeKeys" invRelationField="" />
        </relationships>
      </querySchema>
    </objectGrid>
  </objectGrids>
  <backingMapPluginCollections>
    <backingMapPluginCollection id="Node">
      <bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
        <property name="Name" type="java.lang.String" value="parentNode"/>
<property name="Name" type="java.lang.String" value="parentNodeId"/>
<property name="AttributeName" type="java.lang.String" value="parentNodeId"/>
<property name="RangeIndex" type="boolean" value="false"
 	description="Ranges are not supported for association indexes." />
      </bean>
      <bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
        <property name="Name" type="java.lang.String" value="businessUnitType"/>
        <property name="AttributeName" type="java.lang.String" value="businessUnitTypeKeys"/>

<property name="RangeIndex" type="boolean" value="false"
 	description="Ranges are not supported for association indexes." />
   </bean>
      <bean id="MapIndexPlugin" className="com.ibm.websphere.objectgrid.plugins.index.HashIndex" >
<property name="Name" type="java.lang.String" value="childrenNodeIds"/>
 	<property name="AttributeName" type="java.lang.String" value="childrenNodeIds"/>     
  <property name="RangeIndex" type="boolean" value="false"
 					description="Ranges are not supported for association indexes." />
</bean>
    </backingMapPluginCollection>
  </backingMapPluginCollections>
</objectGridConfig>

Dadas as configurações de índice acima, o exemplos de consulta do objeto são otimizados:

SELECT n FROM Node n WHERE n.parentNodeId is null
SELECT n FROM Node n WHERE n.businessUnitTypeKeys is EMPTY
SELECT n FROM Node n WHERE size(n.businessUnitTypeKeys)>=10
SELECT n FROM BusinessUnitType b, Node n WHERE b member of n.businessUnitTypeKeys and b.name='TELECOM'