提交 545e625f 编写于 作者: V Vlad Ilyushchenko

GRIFFIN: optimised 'and' and 'or' operators to recognise constant conditions...

GRIFFIN: optimised 'and' and 'or' operators to recognise constant conditions better and avoid unnecessary data processing.
GRIFFIN: '=' impl for SYMBOL = CHAR, STRING = CHAR
GRIFFIN: 'sum' performance optimisation
上级 c90a9450
......@@ -85,6 +85,36 @@ class CompactMapValue implements MapValue {
entries.putLong(o, entries.getLong(o) + value);
}
@Override
public void addByte(int index, byte value) {
final long o = getValueColumnOffset(index);
entries.putByte(o, (byte) (entries.getByte(o) + value));
}
@Override
public void addShort(int index, short value) {
final long o = getValueColumnOffset(index);
entries.putShort(o, (short) (entries.getShort(o) + value));
}
@Override
public void addInt(int index, int value) {
final long o = getValueColumnOffset(index);
entries.putInt(o, entries.getInt(o) + value);
}
@Override
public void addDouble(int index, double value) {
final long o = getValueColumnOffset(index);
entries.putDouble(o, entries.getDouble(o) + value);
}
@Override
public void addFloat(int index, float value) {
final long o = getValueColumnOffset(index);
entries.putFloat(o, entries.getFloat(o) + value);
}
@Override
public short getShort(int columnIndex) {
return entries.getShort(getValueColumnOffset(columnIndex));
......
......@@ -136,6 +136,36 @@ final class FastMapValue implements MapValue {
Unsafe.getUnsafe().putLong(p, Unsafe.getUnsafe().getLong(p) + value);
}
@Override
public void addByte(int index, byte value) {
final long p = address0(index);
Unsafe.getUnsafe().putByte(p, (byte) (Unsafe.getUnsafe().getByte(p) + value));
}
@Override
public void addShort(int index, short value) {
final long p = address0(index);
Unsafe.getUnsafe().putShort(p, (short) (Unsafe.getUnsafe().getShort(p) + value));
}
@Override
public void addInt(int index, int value) {
final long p = address0(index);
Unsafe.getUnsafe().putInt(p, Unsafe.getUnsafe().getInt(p) + value);
}
@Override
public void addDouble(int index, double value) {
final long p = address0(index);
Unsafe.getUnsafe().putDouble(p, Unsafe.getUnsafe().getDouble(p) + value);
}
@Override
public void addFloat(int index, float value) {
final long p = address0(index);
Unsafe.getUnsafe().putFloat(p, Unsafe.getUnsafe().getFloat(p) + value);
}
@Override
public void putShort(int index, short value) {
Unsafe.getUnsafe().putShort(address0(index), value);
......
......@@ -55,20 +55,30 @@ public interface MapValue extends Record {
void putByte(int index, byte value);
void addByte(int index, byte value);
void putDate(int index, long value);
void putDouble(int index, double value);
void addDouble(int index, double value);
void putFloat(int index, float value);
void addFloat(int index, float value);
void putInt(int index, int value);
void addInt(int index, int value);
void putLong(int index, long value);
void addLong(int index, long value);
void putShort(int index, short value);
void addShort(int index, short value);
void putChar(int index, char value);
void putTimestamp(int columnIndex, long value);
......
......@@ -29,6 +29,7 @@ import io.questdb.cairo.sql.Record;
import io.questdb.griffin.FunctionFactory;
import io.questdb.griffin.engine.functions.BinaryFunction;
import io.questdb.griffin.engine.functions.BooleanFunction;
import io.questdb.griffin.engine.functions.constants.BooleanConstant;
import io.questdb.std.ObjList;
public class AndFunctionFactory implements FunctionFactory {
......@@ -39,7 +40,22 @@ public class AndFunctionFactory implements FunctionFactory {
@Override
public Function newInstance(ObjList<Function> args, int position, CairoConfiguration configuration) {
return new MyBooleanFunction(position, args.getQuick(0), args.getQuick(1));
Function leftFunc = args.getQuick(0);
Function rightFunc = args.getQuick(1);
if (leftFunc.isConstant()) {
if (leftFunc.getBool(null)) {
return rightFunc;
}
return new BooleanConstant(position, false);
}
if (rightFunc.isConstant()) {
if (rightFunc.getBool(null)) {
return leftFunc;
}
return new BooleanConstant(position, false);
}
return new MyBooleanFunction(position, leftFunc, rightFunc);
}
private static class MyBooleanFunction extends BooleanFunction implements BinaryFunction {
......
......@@ -29,6 +29,7 @@ import io.questdb.cairo.sql.Record;
import io.questdb.griffin.FunctionFactory;
import io.questdb.griffin.engine.functions.BinaryFunction;
import io.questdb.griffin.engine.functions.BooleanFunction;
import io.questdb.griffin.engine.functions.constants.BooleanConstant;
import io.questdb.std.ObjList;
public class OrFunctionFactory implements FunctionFactory {
......@@ -39,7 +40,22 @@ public class OrFunctionFactory implements FunctionFactory {
@Override
public Function newInstance(ObjList<Function> args, int position, CairoConfiguration configuration) {
return new MyBooleanFunction(position, args.getQuick(0), args.getQuick(1));
final Function leftFunc = args.getQuick(0);
final Function rightFunc = args.getQuick(1);
if (leftFunc.isConstant()) {
if (leftFunc.getBool(null)) {
return new BooleanConstant(position, true);
}
return rightFunc;
}
if (rightFunc.isConstant()) {
if (rightFunc.getBool(null)) {
return new BooleanConstant(position, true);
}
return leftFunc;
}
return new MyBooleanFunction(position, leftFunc, rightFunc);
}
private static class MyBooleanFunction extends BooleanFunction implements BinaryFunction {
......
......@@ -30,6 +30,8 @@ import io.questdb.griffin.FunctionFactory;
import io.questdb.griffin.engine.functions.BinaryFunction;
import io.questdb.griffin.engine.functions.BooleanFunction;
import io.questdb.griffin.engine.functions.UnaryFunction;
import io.questdb.griffin.engine.functions.constants.BooleanConstant;
import io.questdb.std.Chars;
import io.questdb.std.ObjList;
public class EqStrCharFunctionFactory implements FunctionFactory {
......@@ -45,93 +47,94 @@ public class EqStrCharFunctionFactory implements FunctionFactory {
// length of non-constant (must be -1)
// 2. when one of arguments is constant, save method call and use a field
Function a = args.getQuick(0);
Function b = args.getQuick(1);
Function strFunc = args.getQuick(0);
Function charFunc = args.getQuick(1);
if (a.isConstant() && !b.isConstant()) {
return createHalfConstantFunc(position, a, b);
if (strFunc.isConstant() && !charFunc.isConstant()) {
CharSequence str = strFunc.getStr(null);
if (str == null || str.length() != 1) {
return new BooleanConstant(position, false);
}
return new ConstStrFunc(position, charFunc, str.charAt(0));
}
if (!a.isConstant() && b.isConstant()) {
return createHalfConstantFunc(position, b, a);
if (!strFunc.isConstant() && charFunc.isConstant()) {
return new ConstChrFunc(position, strFunc, charFunc.getChar(null));
}
return new Func(position, a, b);
}
if (strFunc.isConstant() && charFunc.isConstant()) {
return new BooleanConstant(position, Chars.equalsNc(strFunc.getStr(null), charFunc.getChar(null)));
}
private Function createHalfConstantFunc(int position, Function constFunc, Function varFunc) {
return new ConstCheckFunc(position, varFunc, constFunc.getChar(null));
return new Func(position, strFunc, charFunc);
}
private static class ConstCheckFunc extends BooleanFunction implements UnaryFunction {
private final Function arg;
private final char constant;
private static class ConstChrFunc extends BooleanFunction implements UnaryFunction {
private final Function strFunc;
private final char chrConst;
public ConstCheckFunc(int position, Function arg, char constant) {
public ConstChrFunc(int position, Function strFunc, char chrConst) {
super(position);
this.arg = arg;
this.constant = constant;
this.strFunc = strFunc;
this.chrConst = chrConst;
}
@Override
public Function getArg() {
return arg;
return strFunc;
}
@Override
public boolean getBool(Record rec) {
CharSequence value = arg.getStr(rec);
if (value == null) {
return false;
}
return Chars.equalsNc(strFunc.getStr(rec), chrConst);
}
}
final int len = value.length();
if (len == 0) {
return false;
}
return value.charAt(0) == constant;
private static class ConstStrFunc extends BooleanFunction implements UnaryFunction {
private final Function chrFunc;
private final char chrConst;
public ConstStrFunc(int position, Function chrFunc, char chrConst) {
super(position);
this.chrFunc = chrFunc;
this.chrConst = chrConst;
}
@Override
public Function getArg() {
return chrFunc;
}
@Override
public boolean getBool(Record rec) {
return chrFunc.getChar(rec) == chrConst;
}
}
private static class Func extends BooleanFunction implements BinaryFunction {
private final Function left;
private final Function right;
private final Function strFunc;
private final Function chrFunc;
public Func(int position, Function left, Function right) {
public Func(int position, Function strFunc, Function chrFunc) {
super(position);
this.left = left;
this.right = right;
this.strFunc = strFunc;
this.chrFunc = chrFunc;
}
@Override
public Function getLeft() {
return left;
return strFunc;
}
@Override
public Function getRight() {
return right;
return chrFunc;
}
@Override
public boolean getBool(Record rec) {
// important to compare A and B strings in case
// these are columns of the same record
// records have re-usable character sequences
final CharSequence a = left.getStr(rec);
final char b = right.getChar(rec);
if (a == null) {
return false;
}
int len = a.length();
if (len == 0) {
return false;
}
return a.charAt(0) == b;
return Chars.equalsNc(strFunc.getStr(rec), chrFunc.getChar(rec));
}
}
}
/*******************************************************************************
* ___ _ ____ ____
* / _ \ _ _ ___ ___| |_| _ \| __ )
* | | | | | | |/ _ \/ __| __| | | | _ \
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
* \__\_\\__,_|\___||___/\__|____/|____/
*
* Copyright (C) 2014-2019 Appsicle
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package io.questdb.griffin.engine.functions.eq;
import io.questdb.cairo.CairoConfiguration;
import io.questdb.cairo.sql.Function;
import io.questdb.cairo.sql.Record;
import io.questdb.cairo.sql.RecordCursor;
import io.questdb.cairo.sql.SymbolTable;
import io.questdb.griffin.FunctionFactory;
import io.questdb.griffin.SqlExecutionContext;
import io.questdb.griffin.engine.functions.BinaryFunction;
import io.questdb.griffin.engine.functions.BooleanFunction;
import io.questdb.griffin.engine.functions.UnaryFunction;
import io.questdb.griffin.engine.functions.columns.SymbolColumn;
import io.questdb.std.Chars;
import io.questdb.std.ObjList;
import io.questdb.std.str.SingleCharCharSequence;
public class EqSymCharFunctionFactory implements FunctionFactory {
@Override
public String getSignature() {
return "=(KA)";
}
@Override
public Function newInstance(ObjList<Function> args, int position, CairoConfiguration configuration) {
// there are optimisation opportunities
// 1. when one of args is constant null comparison can boil down to checking
// length of non-constant (must be -1)
// 2. when one of arguments is constant, save method call and use a field
Function symFunc = args.getQuick(0);
Function chrFunc = args.getQuick(1);
if (chrFunc.isConstant()) {
final char constValue = chrFunc.getChar(null);
if (symFunc instanceof SymbolColumn) {
return new ConstCheckColumnFunc(position, (SymbolColumn) symFunc, constValue);
} else {
return new ConstCheckFunc(position, symFunc, constValue);
}
}
return new Func(position, symFunc, chrFunc);
}
private static class ConstCheckFunc extends BooleanFunction implements UnaryFunction {
private final Function symFunc;
private final char constant;
public ConstCheckFunc(int position, Function symFunc, char constant) {
super(position);
this.symFunc = symFunc;
this.constant = constant;
}
@Override
public Function getArg() {
return symFunc;
}
@Override
public boolean getBool(Record rec) {
return Chars.equalsNc(symFunc.getSymbol(rec), constant);
}
}
private static class ConstCheckColumnFunc extends BooleanFunction implements UnaryFunction {
private final SymbolColumn arg;
private final char constant;
private int valueIndex;
public ConstCheckColumnFunc(int position, SymbolColumn arg, char constant) {
super(position);
this.arg = arg;
this.constant = constant;
}
@Override
public Function getArg() {
return arg;
}
@Override
public boolean getBool(Record rec) {
if (valueIndex == SymbolTable.VALUE_NOT_FOUND) {
return false;
}
return arg.getInt(rec) == valueIndex;
}
@Override
public void init(RecordCursor recordCursor, SqlExecutionContext executionContext) {
valueIndex = recordCursor.getSymbolTable(arg.getColumnIndex()).getQuick(SingleCharCharSequence.get(constant));
}
}
private static class Func extends BooleanFunction implements BinaryFunction {
private final Function symFunc;
private final Function chrFunc;
public Func(int position, Function symFunc, Function chrFunc) {
super(position);
this.symFunc = symFunc;
this.chrFunc = chrFunc;
}
@Override
public Function getLeft() {
return symFunc;
}
@Override
public Function getRight() {
return chrFunc;
}
@Override
public boolean getBool(Record rec) {
// important to compare A and B strings in case
// these are columns of the same record
// records have re-usable character sequences
final CharSequence a = symFunc.getSymbol(rec);
final char b = chrFunc.getChar(rec);
if (a == null || a.length() != 1) {
return false;
}
return a.charAt(0) == b;
}
}
}
......@@ -26,10 +26,14 @@ package io.questdb.griffin.engine.functions.eq;
import io.questdb.cairo.CairoConfiguration;
import io.questdb.cairo.sql.Function;
import io.questdb.cairo.sql.Record;
import io.questdb.cairo.sql.RecordCursor;
import io.questdb.cairo.sql.SymbolTable;
import io.questdb.griffin.FunctionFactory;
import io.questdb.griffin.SqlExecutionContext;
import io.questdb.griffin.engine.functions.BinaryFunction;
import io.questdb.griffin.engine.functions.BooleanFunction;
import io.questdb.griffin.engine.functions.UnaryFunction;
import io.questdb.griffin.engine.functions.columns.SymbolColumn;
import io.questdb.std.Chars;
import io.questdb.std.ObjList;
......@@ -46,28 +50,29 @@ public class EqSymStrFunctionFactory implements FunctionFactory {
// length of non-constant (must be -1)
// 2. when one of arguments is constant, save method call and use a field
Function a = args.getQuick(0);
Function b = args.getQuick(1);
Function symFunc = args.getQuick(0);
Function strFunc = args.getQuick(1);
if (a.isConstant() && !b.isConstant()) {
return createHalfConstantFunc(position, a, b);
// SYMBOL cannot be constant
if (strFunc.isConstant()) {
return createHalfConstantFunc(position, strFunc, symFunc);
}
if (!a.isConstant() && b.isConstant()) {
return createHalfConstantFunc(position, b, a);
}
return new Func(position, a, b);
return new Func(position, symFunc, strFunc);
}
private Function createHalfConstantFunc(int position, Function constFunc, Function varFunc) {
CharSequence constValue = constFunc.getStr(null);
if (constValue == null) {
return new NullCheckFunc(position, varFunc);
if (varFunc instanceof SymbolColumn) {
if (constValue == null) {
return new NullCheckColumnFunc(position, varFunc);
}
return new ConstCheckColumnFunc(position, (SymbolColumn) varFunc, constValue);
} else {
if (constValue == null) {
return new NullCheckFunc(position, varFunc);
}
return new ConstCheckFunc(position, varFunc, constValue);
}
return new ConstCheckFunc(position, varFunc, constValue);
}
private static class NullCheckFunc extends BooleanFunction implements UnaryFunction {
......@@ -89,6 +94,30 @@ public class EqSymStrFunctionFactory implements FunctionFactory {
}
}
private static class NullCheckColumnFunc extends BooleanFunction implements UnaryFunction {
private final Function arg;
public NullCheckColumnFunc(int position, Function arg) {
super(position);
this.arg = arg;
}
@Override
public Function getArg() {
return arg;
}
@Override
public boolean getBool(Record rec) {
return arg.getInt(rec) == SymbolTable.VALUE_IS_NULL;
}
@Override
public void init(RecordCursor recordCursor, SqlExecutionContext executionContext) {
}
}
private static class ConstCheckFunc extends BooleanFunction implements UnaryFunction {
private final Function arg;
private final CharSequence constant;
......@@ -110,6 +139,36 @@ public class EqSymStrFunctionFactory implements FunctionFactory {
}
}
private static class ConstCheckColumnFunc extends BooleanFunction implements UnaryFunction {
private final SymbolColumn arg;
private final CharSequence constant;
private int valueIndex;
public ConstCheckColumnFunc(int position, SymbolColumn arg, CharSequence constant) {
super(position);
this.arg = arg;
this.constant = constant;
}
@Override
public Function getArg() {
return arg;
}
@Override
public boolean getBool(Record rec) {
if (valueIndex == SymbolTable.VALUE_NOT_FOUND) {
return false;
}
return arg.getInt(rec) == valueIndex;
}
@Override
public void init(RecordCursor recordCursor, SqlExecutionContext executionContext) {
valueIndex = recordCursor.getSymbolTable(arg.getColumnIndex()).getQuick(constant);
}
}
private static class Func extends BooleanFunction implements BinaryFunction {
private final Function left;
......@@ -143,7 +202,7 @@ public class EqSymStrFunctionFactory implements FunctionFactory {
return b == null;
}
return b != null && Chars.equals(a, b);
return Chars.equalsNc(a, b);
}
}
}
......@@ -48,7 +48,7 @@ public class SumByteGroupByFunction extends ByteFunction implements GroupByFunct
@Override
public void computeNext(MapValue mapValue, Record record) {
mapValue.putByte(valueIndex, (byte) (mapValue.getByte(valueIndex) + value.getByte(record)));
mapValue.addByte(valueIndex, value.getByte(record));
}
@Override
......
......@@ -48,7 +48,7 @@ public class SumDoubleGroupByFunction extends DoubleFunction implements GroupByF
@Override
public void computeNext(MapValue mapValue, Record record) {
mapValue.putDouble(valueIndex, mapValue.getDouble(valueIndex) + value.getDouble(record));
mapValue.addDouble(valueIndex, value.getDouble(record));
}
@Override
......
......@@ -48,7 +48,7 @@ public class SumFloatGroupByFunction extends FloatFunction implements GroupByFun
@Override
public void computeNext(MapValue mapValue, Record record) {
mapValue.putFloat(valueIndex, mapValue.getFloat(valueIndex) + value.getFloat(record));
mapValue.addFloat(valueIndex, value.getFloat(record));
}
@Override
......
......@@ -49,7 +49,7 @@ public class SumIntGroupByFunction extends IntFunction implements GroupByFunctio
@Override
public void computeNext(MapValue mapValue, Record record) {
mapValue.putInt(valueIndex, mapValue.getInt(valueIndex) + value.getInt(record));
mapValue.addInt(valueIndex, value.getInt(record));
}
@Override
......
......@@ -48,7 +48,7 @@ public class SumShortGroupByFunction extends ShortFunction implements GroupByFun
@Override
public void computeNext(MapValue mapValue, Record record) {
mapValue.putShort(valueIndex, (short) (mapValue.getShort(valueIndex) + value.getShort(record)));
mapValue.addShort(valueIndex, value.getShort(record));
}
@Override
......
......@@ -168,6 +168,10 @@ public final class Chars {
return l.length() == 1 && l.charAt(0) == r;
}
public static boolean equalsNc(CharSequence l, char r) {
return l != null && equals(l, r);
}
/**
* Compares two char sequences on assumption and right value is always lower case.
* Methods converts every char of right sequence before comparing to left sequence.
......
/*******************************************************************************
* ___ _ ____ ____
* / _ \ _ _ ___ ___| |_| _ \| __ )
* | | | | | | |/ _ \/ __| __| | | | _ \
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
* \__\_\\__,_|\___||___/\__|____/|____/
*
* Copyright (C) 2014-2019 Appsicle
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package io.questdb.std.str;
import io.questdb.std.ThreadLocal;
public final class SingleCharCharSequence extends AbstractCharSequence {
private static final ThreadLocal<SingleCharCharSequence> TL_CHAR_SEQUENCE = new ThreadLocal<>(SingleCharCharSequence::new);
private char value;
public static CharSequence get(char value) {
final SingleCharCharSequence that = TL_CHAR_SEQUENCE.get();
that.value = value;
return that;
}
@Override
public int length() {
return 1;
}
@Override
public char charAt(int index) {
return value;
}
}
......@@ -21,7 +21,6 @@
#
################################################################################
################################################################################
# ___ _ ____ ____
# / _ \ _ _ ___ ___| |_| _ \| __ )
......@@ -57,6 +56,8 @@ io.questdb.griffin.engine.functions.eq.EqDoubleFunctionFactory
io.questdb.griffin.engine.functions.eq.EqLong256StrFunctionFactory
io.questdb.griffin.engine.functions.eq.EqLong256FunctionFactory
io.questdb.griffin.engine.functions.eq.EqStrCharFunctionFactory
io.questdb.griffin.engine.functions.eq.EqSymStrFunctionFactory
io.questdb.griffin.engine.functions.eq.EqSymCharFunctionFactory
# '<>'
io.questdb.griffin.engine.functions.eq.NotEqStrFunctionFactory
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册