乌鸦查询有时只有效
Raven query only works sometimes
我们一直遇到以下查询 raven 数据库的方法有效的问题,但只有大约 90% 的时间
member.UserId = userService.GivenUsernameGetUserId(command.EmailAddress.ToLower());
为了解决这个问题,我做了这个丑陋的 hack 解决方法,它似乎确实解决了这个问题:
member.UserId = userService.GivenUsernameGetUserId(command.EmailAddress.ToLower());
System.Threading.Thread.Sleep(1000);
if (member.UserId.IsNullOrEmpty())
{
logger.Error("the userid was not loaded in time");
for (int i = 0; i < 5; i++)
{
member.UserId = userService.GivenUsernameGetUserId(command.EmailAddress.ToLower());
System.Threading.Thread.Sleep(1000);
if (member.UserId.IsNotNullOrEmpty())
{
logger.Info("The userid was retrieved in a loop after some delay ");
break;
}
}
if (member.UserId.IsNullOrEmpty())
{
logger.Error("a loop of 5 cycles was run trying to retrieve the userId but couldn't get it.");
}
}
谁能看出为什么它有时只能检索正确的数据,是否有更优雅的解决方案来确保它一直尝试直到检索到数据?我在想是否有一些基本的超时设置可以在 web.config 或其他东西中设置?
问题可能是过时的索引:用户是最近创建的,索引还没有机会更新。 (通常这需要几毫秒,但在大型数据库上可能需要更长的时间。)
您可以在此处执行 3 项操作来解决您的问题:
- 选项 1:根据电子邮件地址创建用户 ID。那么你根本不必弄乱索引。
- 选项 2:您可以保留用户 ID as-is,但等待 non-stale 个索引。
- 选项 3:创建用户时,等待索引更新。
我将在下面描述每个选项:
选项 1:
创建您的用户 ID well-known,这样您就根本不需要用户索引了。
假设你的对象叫做用户。当您注册用户时,您的代码将如下所示:
public void RegisterUser(string emailAddress)
{
var user = new User
{
UserName = emailAddress,
...
};
// Give the User a well-known ID, so that we don't have to mess with indexes later.
user.Id = "Users/" + emailAddress;
ravenSession.Store(user);
}
如果你这样做了,你就根本不用弄乱索引了。当需要加载您的用户时:
public string GivenUsernameGetUserId(string userName)
{
// Look ma, no query needed.
return "Users/" + userName;
// Or, need to return the User itself? You can use .Load, which will never be stale.
// return ravenSession.Load<User>("Users/" + userName);
}
这确实是您的最佳选择,您永远不必处理索引,因此,您永远不必处理过时的数据。
选项 2
选项 2 是使用 .WaitForNonStaleResults。它在返回结果之前等待索引变为 up-to-date。
public string GivenUsernameGetUserId(string userName)
{
// Use .WaitForNonStaleResultsAsOfNow()
return ravenSession.Query<User>()
.Customize(x => x.WaitForNonStaleResultsAsOfNow())
.Where(u => u.UserName == userName)
.Select(u => u.Id)
.FirstOrDefault();
}
选项 3
选项 3 是在 保存 您的用户时等待索引更新。
这需要 Raven 3.5 或更高版本。
public void RegisterUser(string userName)
{
ravenSession.Advanced.WaitForIndexesAfterSaveChanges(timeout: TimeSpan.FromSeconds(30));
var user = new User {...};
ravenSession.Store(user);
ravenSession.SaveChanges(); // This won't return until the User is stored *AND* the indexes are updated.
};
就个人而言,我建议为您的用户使用#1: well-known ID。此外,即使您实施其他解决方案,我也推荐#3:SaveChanges 将在返回之前等待索引更新。这将减少过时索引的意外情况,因此我通常推荐它。
我正在使用 Raven DB 3.5 并使用提到的 选项 3
这确实有效,但我在使用这种方法时遇到了问题:
在特定用例中,此操作大约需要 60 秒才能完成。
我不建议普遍使用 WaitForIndexesAfterSaveChanges()
,因为它显然会导致巨大的性能问题。
相反,我会使用 WaitForNonStaleResultsAsOfNow()
.
配置查询
我们一直遇到以下查询 raven 数据库的方法有效的问题,但只有大约 90% 的时间
member.UserId = userService.GivenUsernameGetUserId(command.EmailAddress.ToLower());
为了解决这个问题,我做了这个丑陋的 hack 解决方法,它似乎确实解决了这个问题:
member.UserId = userService.GivenUsernameGetUserId(command.EmailAddress.ToLower());
System.Threading.Thread.Sleep(1000);
if (member.UserId.IsNullOrEmpty())
{
logger.Error("the userid was not loaded in time");
for (int i = 0; i < 5; i++)
{
member.UserId = userService.GivenUsernameGetUserId(command.EmailAddress.ToLower());
System.Threading.Thread.Sleep(1000);
if (member.UserId.IsNotNullOrEmpty())
{
logger.Info("The userid was retrieved in a loop after some delay ");
break;
}
}
if (member.UserId.IsNullOrEmpty())
{
logger.Error("a loop of 5 cycles was run trying to retrieve the userId but couldn't get it.");
}
}
谁能看出为什么它有时只能检索正确的数据,是否有更优雅的解决方案来确保它一直尝试直到检索到数据?我在想是否有一些基本的超时设置可以在 web.config 或其他东西中设置?
问题可能是过时的索引:用户是最近创建的,索引还没有机会更新。 (通常这需要几毫秒,但在大型数据库上可能需要更长的时间。)
您可以在此处执行 3 项操作来解决您的问题:
- 选项 1:根据电子邮件地址创建用户 ID。那么你根本不必弄乱索引。
- 选项 2:您可以保留用户 ID as-is,但等待 non-stale 个索引。
- 选项 3:创建用户时,等待索引更新。
我将在下面描述每个选项:
选项 1:
创建您的用户 ID well-known,这样您就根本不需要用户索引了。
假设你的对象叫做用户。当您注册用户时,您的代码将如下所示:
public void RegisterUser(string emailAddress)
{
var user = new User
{
UserName = emailAddress,
...
};
// Give the User a well-known ID, so that we don't have to mess with indexes later.
user.Id = "Users/" + emailAddress;
ravenSession.Store(user);
}
如果你这样做了,你就根本不用弄乱索引了。当需要加载您的用户时:
public string GivenUsernameGetUserId(string userName)
{
// Look ma, no query needed.
return "Users/" + userName;
// Or, need to return the User itself? You can use .Load, which will never be stale.
// return ravenSession.Load<User>("Users/" + userName);
}
这确实是您的最佳选择,您永远不必处理索引,因此,您永远不必处理过时的数据。
选项 2
选项 2 是使用 .WaitForNonStaleResults。它在返回结果之前等待索引变为 up-to-date。
public string GivenUsernameGetUserId(string userName)
{
// Use .WaitForNonStaleResultsAsOfNow()
return ravenSession.Query<User>()
.Customize(x => x.WaitForNonStaleResultsAsOfNow())
.Where(u => u.UserName == userName)
.Select(u => u.Id)
.FirstOrDefault();
}
选项 3
选项 3 是在 保存 您的用户时等待索引更新。
这需要 Raven 3.5 或更高版本。
public void RegisterUser(string userName)
{
ravenSession.Advanced.WaitForIndexesAfterSaveChanges(timeout: TimeSpan.FromSeconds(30));
var user = new User {...};
ravenSession.Store(user);
ravenSession.SaveChanges(); // This won't return until the User is stored *AND* the indexes are updated.
};
就个人而言,我建议为您的用户使用#1: well-known ID。此外,即使您实施其他解决方案,我也推荐#3:SaveChanges 将在返回之前等待索引更新。这将减少过时索引的意外情况,因此我通常推荐它。
我正在使用 Raven DB 3.5 并使用提到的 选项 3
这确实有效,但我在使用这种方法时遇到了问题:
在特定用例中,此操作大约需要 60 秒才能完成。
我不建议普遍使用 WaitForIndexesAfterSaveChanges()
,因为它显然会导致巨大的性能问题。
相反,我会使用 WaitForNonStaleResultsAsOfNow()
.