La définition et l'utilisation adéquates des index peut considérablement améliorer les performances des requêtes.
Les requêtes WebSphere eXtreme Scale peuvent utiliser les plug-in HashIndex pré-intégrés pour améliorer leurs performances. Les index peuvent être définis sur des entités ou sur des attributs d'objets. Le moteur de requête utilisera automatiquement les index définis si sa clause WHERE utilise l'une des chaînes suivantes :
Pour plus d'informations sur la configuration de HashIndex, voir Plug-in d'indexation des données.
Pour plus d'informations sur l'indexation, voir Indexation.
Pour une manière plus efficace de rechercher les objets mis en cache, voir Utilisation d'un index composite.
La méthode setHint des interfaces Query et ObjectQuery, utilisée avec la constante HINT_USEINDEX, permet de sélectionner manuellement un index. Cela peut être utile lorsqu'on cherche à optimiser une requête pour qu'elle utilise l'index le plus performant.
L'exemple qui suit utilise des termes simples : e.empid, e.name, e.salary, d.name, d.budget et e.isManager. Ces exemples présupposent que des index sont définis sur les zones name, salary et budget d'une entité ou d'un objet value. La zone empid est une clé primaire et aucun index n'est défini pour isManager.
La requête suivante utilise les deux index sur les zones name et salary. Elle renvoie tous les salariés dont les noms égalent la valeur du premier paramètre ou un salaire égal à la valeur du second paramètre :
SELECT e FROM EmpBean e where e.name=?1 or e.salary=?2
La requête suivante utilise les deux index sur les zones name et budget. La requête retourne tous les départements nommés "DEV" dont le budget est supérieur à 2000.
SELECT d FROM DeptBean dwhere d.name='DEV' and d.budget>2000
La requête suivante retourne tous les salariés dont le salaire est supérieur à 3000 et dont la valeur de l'indicateur isManager égale celle du paramètre. La requête utilise l'index qui est défini sur la zone salary et elle procède à un filtrage supplémentaire en évaluant l'expression de comparaison e.isManager=?1.
SELECT e FROM EmpBean e where e.salary>3000 and e.isManager=?1
La requête suivante recherche tous les salariés qui gagnent plus que le premier paramètre ou tous les salariés qui sont un manager. Bien qu'un index soit défini pour la zone salary, la requête examine l'index qui est automatiquement généré sur les clés primaires de la zone EmpBean et elle évalue l'expression e.salary>?1 ou e.isManager=TRUE.
SELECT e FROM EmpBean e WHERE e.salary>?1 or e.isManager=TRUE
La requête suivante retourne les salariés dont le nom contient la lettre a. Bien qu'un index soit défini pour la zone name, la requête n'utilise pas cet index car la zone name est utilisée dans l'expression LIKE.
SELECT e FROM EmpBean e WHERE e.name LIKE '%a%'
La requête suivante recherche tous les employés dont le nom n'est pas "Smith". Bien qu'un index soit défini pour la zone name, la requête n'utilise pas cet index car elle utilise l'opérateur de comparaison différent de ( <> ).
SELECT e FROM EmpBean e where e.name<>'Smith'
La requête suivante recherche tous les départements dont le budget est inférieur à la valeur du paramètre et qui ont un salarié dont la rémunération est supérieure à 3000. La requête utilise un index pour le salaire mais elle n'utilise pas d'index pour le budget car dept.budget n'est pas un terme simple. Les objets dept sont dérivés de la collection e. L'on n'a pas besoin d'utiliser l'index budget pour rechercher des objets dept.
SELECT dept from EmpBean e, in (e.dept) dept where e.salary>3000 and dept.budget<?
La requête suivante recherche tous les salariés dont la rémunération est supérieure à celles des salariés dont l'empid est 1, 2 et 3. L'index salary n'est pas utilisé car la comparaison implique une sous-requête. La zone empid est néanmoins une clé primaire et elle est utilisée pour une recherche d'index unique car un index est automatiquement prédéfini pour les clés primaires.
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)
Pour vérifier si l'index est en cours d'utilisation par la requête, l'on peut visualiser le Plan de requête. Voici un exemple de plan pour la requête précédente :
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 )
Les index peuvent être définis sur n'importe quel type individuel d'attribut, moyennant les contraintes définies plus haut.
Définir des index d'entités à l'aide de l'annotation @Index
Pour définir un index sur une entité, il suffit de définir une annotation :
Entités utilisant des annotations
@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;
}
Avec XML
Entités sans annotations
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 ObjectGrid avec index d'attributs
<?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>
XML d'entités
<?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>
Définir dans XML des index de non-entités
Les index des types non-entité sont définis dans XML. Il n'existe aucune différence lorsqu'on crée le MapIndexPlugin pour des mappes d'entités ou pour des mappes de non-entités.
Bean Java
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 ObjectGrid avec index d'attributs
<?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>
WebSphere eXtreme Scale stocke au sein de l'objet parent les clés externes des entités en rapport. Dans le cas d'entités, les clés sont stockées dans le tuple sous-jacent. Pour les objets non-entités, les clés sont stockées de manière explicite dans l'objet parent.
L'ajout d'index sur un attribut relationship peut donner un coup d'accélérateur aux requêtes qui utilisent des références cycliques ou qui utilisent les filtres de requête IS NULL, IS EMPTY, SIZE ou MEMBER OF. Les associations, aussi bien monovaleur que multivaleur, peuvent comporter l'annotation @Index ou avoir une configuration de plug-in HashIndex dans le fichier XML du descripteur.
Définir des index de relations d'entités à l'aide de l'annotation @Index
L'exemple qui suit définit des entités avec des annotations @Index :
Entité avec annotation
@Entity
public class Node {
@ManyToOne @Index
Node parentNode;
@OneToMany @Index
List<Node> childrenNodes = new ArrayList();
@OneToMany @Index
List<BusinessUnitType> businessUnitTypes = new ArrayList();
}
Définir des index de relations d'entités à l'aide de XML
L'exemple qui suit définit les mêmes entités et les mêmes index, mais cette fois à l'aide de XML et avec des plug-in HashIndex :
Entité sans annotations
public class Node {
int nodeId;
Node parentNode;
List<Node> childrenNodes = new ArrayList();
List<BusinessUnitType> businessUnitTypes = new ArrayList();
}
XML 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_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>
XML d'entités
<?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>
Avec les index définis plus haut, les exemples suivants de requêtes d'entités sont optimisés :
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'
Définir des index de relations de non-entités
L'exemple qui suit définit un plug-in HashIndex pour des mappes de non-entités dans un fichier XML de descripteur d'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>
Compte tenu des configurations d'index ci-dessus, les exemples suivants de requêtes d'objets sont optimisés :
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'