使用 Redis 实现排序、搜索和分页以获得最佳性能的最佳方式
Best way to implement sort, search & pagination with Redis for maximum performance
我有大约 1,00,000 个员工的大数据。我已将此数据存储到一个名为 "employess" 的 Redis 键中。现在有一个屏幕,我想在其中对某些字段执行搜索并对每一列进行排序以及分页。
为此,我创建了以下运行良好的代码。但平均需要 1.2 秒到 2 秒左右的时间。
我想将它减少到 200 毫秒(要求)
有人可以指导我如何实现该性能或我在以下代码中做错了什么。
我正在使用 C# 代码和 ServiceStack.Redis 客户端。如果需要,我可以自由使用任何其他 Redis 客户端。
public class Employee
{
public int EmployeeId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public DateTime DOB { get; set; }
public char Gender { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string Department { get; set; }
public string Occupation { get; set; }
public decimal Salary { get; set; }
}
// 处理排序、搜索、分页和从 Redis 获取数据的方法。
private GeneralResponse<IEnumerable<Employee>> GetEmp(SearchParam filter, int initialPage, int pageSize, out int totalRecords, out int recordFilterd,
int sortColumn, string sortDirection)
{
var response = new GeneralResponse<IEnumerable<Employee>>();
totalRecords = 0;
recordFilterd = 0;
try
{
var data = Enumerable.Empty<Employee>().AsQueryable();
try
{
using (var redisClient = new RedisClient(Common.redisUrl, Common.redisPort))
{
var rdata = redisClient.Get<IEnumerable<Employee>>("employess");
data = rdata.AsQueryable();
ViewBag.source = "redis";
}
}
catch (Exception e)
{
data = Common.EmployeesList.AsQueryable();
ViewBag.source = "Database";
}
totalRecords = data.Count();
//filter
if (!string.IsNullOrWhiteSpace(filter.FirstName))
{
data = data.Where(x =>
x.FirstName.ToLower().Contains(filter.FirstName.Trim().ToLower())
);
}
if (!string.IsNullOrWhiteSpace(filter.LastName))
{
data = data.Where(x =>
x.LastName.ToLower().Contains(filter.LastName.Trim().ToLower())
);
}
if (!string.IsNullOrWhiteSpace(filter.Department))
{
data = data.Where(x =>
x.Department.ToLower() == filter.Department.Trim().ToLower()
);
}
if (filter.FromDob != null && filter.FromDob != default(DateTime))
{
data = data.Where(x => x.DOB >= filter.FromDob);
}
if (filter.ToDob != null && filter.ToDob != default(DateTime))
{
filter.ToDob = filter.ToDob.AddHours(23).AddMinutes(59);
data = data.Where(x => x.DOB <= filter.ToDob);
}
recordFilterd = data.Count();
//sort
var ascending = sortDirection == "asc";
switch (sortColumn)
{
case 0:
data = data.OrderBy(p => p.EmployeeId, ascending);
break;
case 1:
data = data.OrderBy(p => p.LastName, ascending);
break;
case 2:
data = data.OrderBy(p => p.FirstName, ascending);
break;
case 3:
data = data.OrderBy(p => p.DOB, ascending);
break;
case 4:
data = data.OrderBy(p => p.Gender, ascending);
break;
case 5:
data = data.OrderBy(p => p.Street, ascending);
break;
case 6:
data = data.OrderBy(p => p.City, ascending);
break;
case 7:
data = data.OrderBy(p => p.State, ascending);
break;
case 8:
data = data.OrderBy(p => p.Zip, ascending);
break;
case 9:
data = data.OrderBy(p => p.Department, ascending);
break;
case 10:
data = data.OrderBy(p => p.Occupation, ascending);
break;
case 11:
data = data.OrderBy(p => p.Occupation, ascending);
break;
default:
data = data.OrderBy(p => p.Salary, ascending);
break;
}
data = data
.Skip(initialPage * pageSize)
.Take(pageSize);
var result = data.ToList();
response.Data = result;
}
catch (Exception e)
{
response.Error = true;
response.Exception = e;
}
return response;
}
非常感谢任何帮助或指导。以下是我想要达到速度的参考屏幕。
经过深入研究,我终于发现Redis 不是执行这些操作的好选择。除了这个,我们还可以选择 AWS CloudSearch,它具有完整的排序、搜索和分页功能。
正如上面评论和您的回答中提到的,redis 可能不是解决此问题的最佳选择,而 AWS CloudSearch 可能是解决方案。
在解决类似问题时,我发现我最大的瓶颈是使用'query.Where(x => x.String.Contains(filterText))`。
将全文索引添加到文本搜索列(first/last 您的解决方案的名称)使我们能够以令人满意的性能直接转到 SQL(大约 100 万行需要 100-200 毫秒table)。 https://www.mssqltips.com/sqlservertutorial/9136/sql-server-full-text-indexes/
您好,如果您为每个索引文档添加一个整数 int_id 您可以执行以下查询:'@int_id:[1 10]'。此查询 select 1-10 之间的所有文档。
我有大约 1,00,000 个员工的大数据。我已将此数据存储到一个名为 "employess" 的 Redis 键中。现在有一个屏幕,我想在其中对某些字段执行搜索并对每一列进行排序以及分页。
为此,我创建了以下运行良好的代码。但平均需要 1.2 秒到 2 秒左右的时间。
我想将它减少到 200 毫秒(要求)
有人可以指导我如何实现该性能或我在以下代码中做错了什么。
我正在使用 C# 代码和 ServiceStack.Redis 客户端。如果需要,我可以自由使用任何其他 Redis 客户端。
public class Employee
{
public int EmployeeId { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public DateTime DOB { get; set; }
public char Gender { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string Department { get; set; }
public string Occupation { get; set; }
public decimal Salary { get; set; }
}
// 处理排序、搜索、分页和从 Redis 获取数据的方法。
private GeneralResponse<IEnumerable<Employee>> GetEmp(SearchParam filter, int initialPage, int pageSize, out int totalRecords, out int recordFilterd,
int sortColumn, string sortDirection)
{
var response = new GeneralResponse<IEnumerable<Employee>>();
totalRecords = 0;
recordFilterd = 0;
try
{
var data = Enumerable.Empty<Employee>().AsQueryable();
try
{
using (var redisClient = new RedisClient(Common.redisUrl, Common.redisPort))
{
var rdata = redisClient.Get<IEnumerable<Employee>>("employess");
data = rdata.AsQueryable();
ViewBag.source = "redis";
}
}
catch (Exception e)
{
data = Common.EmployeesList.AsQueryable();
ViewBag.source = "Database";
}
totalRecords = data.Count();
//filter
if (!string.IsNullOrWhiteSpace(filter.FirstName))
{
data = data.Where(x =>
x.FirstName.ToLower().Contains(filter.FirstName.Trim().ToLower())
);
}
if (!string.IsNullOrWhiteSpace(filter.LastName))
{
data = data.Where(x =>
x.LastName.ToLower().Contains(filter.LastName.Trim().ToLower())
);
}
if (!string.IsNullOrWhiteSpace(filter.Department))
{
data = data.Where(x =>
x.Department.ToLower() == filter.Department.Trim().ToLower()
);
}
if (filter.FromDob != null && filter.FromDob != default(DateTime))
{
data = data.Where(x => x.DOB >= filter.FromDob);
}
if (filter.ToDob != null && filter.ToDob != default(DateTime))
{
filter.ToDob = filter.ToDob.AddHours(23).AddMinutes(59);
data = data.Where(x => x.DOB <= filter.ToDob);
}
recordFilterd = data.Count();
//sort
var ascending = sortDirection == "asc";
switch (sortColumn)
{
case 0:
data = data.OrderBy(p => p.EmployeeId, ascending);
break;
case 1:
data = data.OrderBy(p => p.LastName, ascending);
break;
case 2:
data = data.OrderBy(p => p.FirstName, ascending);
break;
case 3:
data = data.OrderBy(p => p.DOB, ascending);
break;
case 4:
data = data.OrderBy(p => p.Gender, ascending);
break;
case 5:
data = data.OrderBy(p => p.Street, ascending);
break;
case 6:
data = data.OrderBy(p => p.City, ascending);
break;
case 7:
data = data.OrderBy(p => p.State, ascending);
break;
case 8:
data = data.OrderBy(p => p.Zip, ascending);
break;
case 9:
data = data.OrderBy(p => p.Department, ascending);
break;
case 10:
data = data.OrderBy(p => p.Occupation, ascending);
break;
case 11:
data = data.OrderBy(p => p.Occupation, ascending);
break;
default:
data = data.OrderBy(p => p.Salary, ascending);
break;
}
data = data
.Skip(initialPage * pageSize)
.Take(pageSize);
var result = data.ToList();
response.Data = result;
}
catch (Exception e)
{
response.Error = true;
response.Exception = e;
}
return response;
}
非常感谢任何帮助或指导。以下是我想要达到速度的参考屏幕。
经过深入研究,我终于发现Redis 不是执行这些操作的好选择。除了这个,我们还可以选择 AWS CloudSearch,它具有完整的排序、搜索和分页功能。
正如上面评论和您的回答中提到的,redis 可能不是解决此问题的最佳选择,而 AWS CloudSearch 可能是解决方案。
在解决类似问题时,我发现我最大的瓶颈是使用'query.Where(x => x.String.Contains(filterText))`。
将全文索引添加到文本搜索列(first/last 您的解决方案的名称)使我们能够以令人满意的性能直接转到 SQL(大约 100 万行需要 100-200 毫秒table)。 https://www.mssqltips.com/sqlservertutorial/9136/sql-server-full-text-indexes/
您好,如果您为每个索引文档添加一个整数 int_id 您可以执行以下查询:'@int_id:[1 10]'。此查询 select 1-10 之间的所有文档。