public JE_Table(TableMeta schema, IRepository repo) { super(schema, repo); indexCodecMap = new HashMap<String, KVCodec>(); KVCodec pkCodec = null; IndexMeta pkIndex = getSchema().getPrimaryIndex(); if (pkCodec == null) { pkCodec = new KVCodec(); pkCodec.setKey_codec( CodecFactory.getInstance(CodecFactory.FIXED_LENGTH).getCodec((pkIndex.getKeyColumns()))); if (pkIndex.getValueColumns() != null) { pkCodec.setValue_codec( CodecFactory.getInstance(CodecFactory.FIXED_LENGTH) .getCodec((pkIndex.getValueColumns()))); } } indexCodecMap.put(pkIndex.getName(), pkCodec); for (IndexMeta secondIndex : getSchema().getSecondaryIndexes()) { KVCodec secCodec = new KVCodec(); secCodec.setKey_codec( CodecFactory.getInstance(CodecFactory.FIXED_LENGTH) .getCodec((secondIndex.getKeyColumns()))); if (secondIndex.getValueColumns() != null) { secCodec.setValue_codec( CodecFactory.getInstance(CodecFactory.FIXED_LENGTH) .getCodec((secondIndex.getValueColumns()))); } indexCodecMap.put(secondIndex.getName(), secCodec); } }
/** * NAME=1的选择性显然比SCHOOL>1好,所以选择二级索引NAME * * @throws QueryException */ @Test public void testChooseIndex列出现的顺序不影响索引选择() throws QueryException { TableNode table1 = new TableNode("TABLE1"); QueryTreeNode qn1 = table1.query("SCHOOL>1&&NAME=1"); qn1.build(); IndexMeta index = IndexChooser.findBestIndex( table1.getTableMeta(), table1.getColumnsRefered(), toDNFFilter(table1.getWhereFilter()), table1.getTableName(), extraCmd); Assert.assertNotNull(index); Assert.assertEquals(index.getName(), "TABLE1._NAME"); TableNode table2 = new TableNode("TABLE1"); QueryTreeNode qn2 = table2.query("NAME=1&&SCHOOL>1"); qn2.build(); index = IndexChooser.findBestIndex( table2.getTableMeta(), table2.getColumnsRefered(), toDNFFilter(table2.getWhereFilter()), table2.getTableName(), extraCmd); Assert.assertNotNull(index); Assert.assertEquals(index.getName(), "TABLE1._NAME"); }
@Override public CloneableRecord get( ExecutionContext context, CloneableRecord key, IndexMeta indexMeta, String dbName) { DatabaseEntry keyEntry = new DatabaseEntry(); DatabaseEntry valueEntry = new DatabaseEntry(); keyEntry.setData(indexCodecMap.get(indexMeta.getName()).getKey_codec().encode(key)); OperationStatus status = getDatabase(dbName) .get( context.getTransaction() == null ? null : ((JE_Transaction) context.getTransaction()).txn, keyEntry, valueEntry, LockMode.DEFAULT); if (OperationStatus.SUCCESS != status) { return null; } if (valueEntry.getSize() != 0) { return indexCodecMap.get(indexMeta.getName()).getValue_codec().decode(valueEntry.getData()); } else { return null; } }
/** 虽然C1,C2上存在组合索引,但是由于范围查询的选择度不如等值查询 因此还是选择了单索引NAME=1 */ @Test public void testChooseIndex单索引选择度好于组合索引() throws QueryException { TableNode table = new TableNode("TABLE9"); QueryTreeNode qn = table.query("C1>10&&C2>3&&NAME=1"); qn.build(); IndexMeta index = IndexChooser.findBestIndex( table.getTableMeta(), table.getColumnsRefered(), toDNFFilter(table.getWhereFilter()), table.getTableName(), extraCmd); Assert.assertNotNull(index); Assert.assertEquals(index.getName(), "TABLE9._NAME"); }
@Test public void testChooseIndex() throws QueryException { TableNode table = new TableNode("TABLE1"); QueryTreeNode qn = table.query("ID=1"); qn.build(); IndexMeta index = IndexChooser.findBestIndex( table.getTableMeta(), emptyColumns, toDNFFilter(table.getWhereFilter()), table.getTableName(), extraCmd); Assert.assertNotNull(index); Assert.assertEquals(index.getName(), "TABLE1"); }
/** C6,C7同时存在组合索引和倒排索引 同时有倒排和组合索引,并且选择度一样,优先选择组合 */ @Test public void testChooseIndex选择度相同优先选组合() throws QueryException { TableNode table = new TableNode("TABLE9"); QueryTreeNode qn = table.query("C6=10&&C7=3"); qn.build(); IndexMeta index = IndexChooser.findBestIndex( table.getTableMeta(), table.getColumnsRefered(), toDNFFilter(table.getWhereFilter()), table.getTableName(), extraCmd); Assert.assertNotNull(index); Assert.assertEquals(index.getName(), "TABLE9._C6_C7"); }
/** * todo:触发更新二级索引 * * @param key * @param value * @throws TddlException */ @Override public void put( ExecutionContext context, CloneableRecord key, CloneableRecord value, IndexMeta indexMeta, String dbName) throws TddlException { DatabaseEntry keyEntry = new DatabaseEntry(); DatabaseEntry valueEntry = new DatabaseEntry(); keyEntry.setData(indexCodecMap.get(indexMeta.getName()).getKey_codec().encode(key)); // 当临时表排序时候可能会用到临时表join,主键插入值为null // if (keyEntry.getData().length == 1 && !isTempTable) { // throw new RuntimeException("pk must not null."); // } if (value != null) { valueEntry.setData(indexCodecMap.get(indexMeta.getName()).getValue_codec().encode(value)); } else { valueEntry = emptyValueEntry; } try { ITransaction transaction = context.getTransaction(); com.sleepycat.je.Transaction txn = null; if (transaction != null && transaction instanceof JE_Transaction) { txn = ((JE_Transaction) transaction).txn; } OperationStatus operationStatus = getDatabase(dbName).put(txn, keyEntry, valueEntry); if (operationStatus.equals(OperationStatus.SUCCESS)) { return; } } catch (LockTimeoutException ex) { throw ex; } catch (ReplicaWriteException ex) { throw new TddlException(ExceptionErrorCodeUtils.Read_only, ex); } }
@Override public void delete( ExecutionContext context, CloneableRecord key, IndexMeta indexMeta, String dbName) throws TddlException { DatabaseEntry keyEntry = new DatabaseEntry(); keyEntry.setData(indexCodecMap.get(indexMeta.getName()).getKey_codec().encode(key)); try { getDatabase(dbName) .delete( context.getTransaction() == null ? null : ((JE_Transaction) context.getTransaction()).txn, keyEntry); } catch (LockTimeoutException ex) { throw ex; } catch (ReplicaWriteException ex) { throw new TddlException(ExceptionErrorCodeUtils.Read_only, ex); } }