4
votes

I have a cache with string as a key and TileKey (class below) as a value, I've noticed that when I execute a query (below) the performance is affected almost linearly by the cache size even though all the fields that are used in the query are indexed.

Here is a representative benchmark - I've used the same query (below) with the same parameters for all benchmarks : The query returns (the same) 30 entries in all benchmarks

  • Query on 5350 entries cache took 6-7ms
  • Query on 10700 entries cache took 8-10ms
  • Query on 48150 entries cache took 30-42ms
  • Query on 96300 entries cache took 50-70ms

I've executed the benchmark with 8gb single node and 4gb 2 nodes, the results were pretty much the same (in terms of query speed relative to cache size)

I've also tried using QuerySqlFieldGroup by using the "time" field as the first group field, it should reduce the result set to only 1000 entries in all benchmarks, i'm not sure that this is the right usage for QuerySqlFieldGroup as from my understanding it should be mainly used for join queries between caches.

Am I doing something wrong or these are the expected query performance using Ignite indexing?

Code :

String strQuery = "time = ? and zoom = ? and x >= ? and x <= ? and y >= ? and y <= ?";
SqlQuery<String, TileKey> query= new SqlQuery<String, TileKey>(TileKey.class, strQuery);
query.setArgs(time, zoom, xMin,xMax,yMin, yMax);
QueryCursor<Entry<String, TileKey>> tileKeyCursor = tileKeyCache.query(query);
Map<String, TileKey> tileKeyMap = new HashMap<String, TileKey>();
for (Entry<String, TileKey> p : keysCursor) {
    tileKeyMap.put(p.getKey(), p.getValue());
}

Cache config :

<bean class="org.apache.ignite.configuration.CacheConfiguration">
            <property name="name" value="KeysCache" />
            <property name="cacheMode" value="PARTITIONED" />
            <property name="atomicityMode" value="ATOMIC" />
            <property name="backups" value="0" />
            <property name="queryIndexEnabled" value="true"/>
            <property name="indexedTypes">
                <list>
                    <value>java.lang.String</value>
                    <value>org.ess.map.TileKey</value>
                </list>
            </property>
</bean>

Class :

@QueryGroupIndex.List(@QueryGroupIndex(name = "idx1"))
public class TileKey implements Serializable {

   /**
    * 
    */
   private static final long serialVersionUID = 1L;

   private String id;

   @QuerySqlField(index = true)
   @QuerySqlField.Group(name = "idx1", order = 0)
   private int time;

   @QuerySqlField(index = true)
   @QuerySqlField.Group(name = "idx1", order = 1)
   private int zoom;

   @QuerySqlField(index = true)
   @QuerySqlField.Group(name = "idx1", order = 2)
   private int x;

   @QuerySqlField(index = true)
   @QuerySqlField.Group(name = "idx1", order = 3)
   private int y;

   @QuerySqlField(index = true)
   private boolean inCache;
}
1
Could you please post a query plan using EXPLAIN? Also I'd recommend to make sure that for each cache size your query returns the same number of entries.Sergi Vladykin

1 Answers

5
votes

I have found the problem, thank you bobby_brew for leading me in the right direction.

The indexing example of Ignite is incorrect, there is an open issue about it.

I've changes the indexed field annotations from

   @QuerySqlField(index = true)
   @QuerySqlField.Group(name = "idx1", order = x)

To

@QuerySqlField(index = true, orderedGroups = {@QuerySqlField.Group(name = "idx1", order = x)})

and now the query duration is solid 2ms in all scenarios