使用daterange创建rails索引到多列查询

时间:2016-06-15 15:37:54

标签: ruby-on-rails postgresql activerecord rails-activerecord postgresql-9.3

我在这两个查询中遇到了一些性能问题:

// Create field to back your "myImplementation" property
FieldBuilder newBackingField = tb.DefineField("backingField_myImplementation", typeof(MyInterface), System.Reflection.FieldAttributes.Private);
// Create your "myImplementation" property
PropertyBuilder newProp = tb.DefineProperty("myImplementation", System.Reflection.PropertyAttributes.None, typeof(MyInterface), Type.EmptyTypes);
// Create get-method for your property
MethodBuilder getter = tb.DefineMethod("get_myImplementation", System.Reflection.MethodAttributes.Private);
ILGenerator getterILGen = getter.GetILGenerator();
// Basic implementation (return backing field value)
getterILGen.Emit(OpCodes.Ldarg_0);
getterILGen.Emit(OpCodes.Ldfld, newBackingField);
getterILGen.Emit(OpCodes.Ret);

// Create set-method for your property
MethodBuilder setter = tb.DefineMethod("set_myImplementation", System.Reflection.MethodAttributes.Private);
setter.DefineParameter(1, System.Reflection.ParameterAttributes.None, "value");
ILGenerator setterILGen = setter.GetILGenerator();
// Basic implementation (set backing field)
setterILGen.Emit(OpCodes.Ldarg_0);
setterILGen.Emit(OpCodes.Ldarg_1);
setterILGen.Emit(OpCodes.Stfld, newBackingField);
setterILGen.Emit(OpCodes.Ret);

// Hello1 Method
MethodBuilder hello1 = tb.DefineMethod("Hello1", System.Reflection.MethodAttributes.Public);
ILGenerator il = hello1.GetILGenerator();

// Here, add code to load arguments, if any (as shown previously in answer)

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, getter);
il.Emit(OpCodes.Callvirt, typeof(MyInterface).GetMethod("Hello1"));
il.Emit(OpCodes.Ret);

他们每个用户拥有大约500,000条记录,并且运行时间超过15秒。

基于此,我想创建两个索引,每个索引一个。

我的问题是,我应该创建的索引是:

any_impression = Impression.exists?(user_id: user_id, created_at: range)
any_visit      = Visit.exists?(user_id: user_id, created_at: range)

或者上面的查询需要更多一些特定信息才能使用创建的索引?

非常感谢。

1 个答案:

答案 0 :(得分:1)

那些索引应该没问题。在Postgres中,索引并不总是知道如何使用给定的运算符 - 它取决于索引类型。 This page from the manual解释了详细信息。

您建议的索引是btree索引。在我的实验中,告诉ActiveRecord根据范围查询时间戳列会产生BETWEEN ... AND ... SQL:

User.where(created_at: (Date.parse('2015-01-01') ..
                        Date.parse('2016-01-01'))).to_sql

给出:

SELECT "users".*
FROM   "users"
WHERE  ("users"."created_at" BETWEEN '2015-01-01' AND '2016-01-01')

这也是你所看到的吗?然后Postgres应该使用您的索引,因为BETWEEN只是<=>=

您也可以手动使用EXPLAINEXPLAIN ANALYZE运行查询,以查看索引是否按预期使用。