【问题标题】:Quickest way to retrieve information from database从数据库中检索信息的最快方法
【发布时间】:2015-06-09 14:41:45
【问题描述】:

我正在尝试解决我目前面临的问题。我正在尝试找出从数据库中检索信息的最快方法。

所以传入了一个经理名称,我需要做的是返回所有传入的经理的用户,但是如果这些用户中的任何一个恰好是经理,我必须返回所有的用户名 (List<String>) 他们也管理...这将重复,直到我返回每个人

这是我需要返回的一个小例子

manager --> manager --> manager --> manager --> employee
        --> manager --> employee
        --> manager --> manager --> manager --> employee
        --> employee

所以在上面的示例中,代码将返回 12 个名称

我知道我可以通过多种不同的方式做到这一点,但我不知道哪种方式是最好的(递归 for 循环、for 循环递归调用方法、SQL 语句、HQL 语句......等等)

由于此列表可以是任何大小,具体取决于传入的管理器,我需要找到最快的方法来检索它,因为我已将其编码为使用递归 for 循环,这需要 1 分 20 秒太长了

有什么想法吗?

【问题讨论】:

  • 如果可能的话,也许你应该尝试用一个查询来完成。表结构如何?
  • 我有一个用户对象,它只有一个经理名称,它是另一个用户对象,但没有与外键或任何东西链接,因此必须使用糟糕的名称进行搜索(不是我的设计,这是我拿到代码时的样子)
  • 数据库中有多少用户?如果可以将它们全部加载到内存中,则可以通过搜索对象层次结构快速执行查询。
  • 1 分 20 秒返回哪个大小的列表?你能改变数据库设计吗?
  • @AdriaanKoster : 目前数据库中有超过 13000 名用户,并且会不断增长

标签: java spring hibernate loops for-loop


【解决方案1】:

您需要执行性能分析,以了解延迟是来自数据库、应用程序服务器还是网络(由于许多循环导致延迟)。 根据您的数据,我认为您进行了太多查询,但这是您应该验证的假设。

在我的公司,这是一家大公司,大老板和任何员工之间的等级不超过15级。因此,您不必执行超过 15 个请求。

我怀疑你为每个人做一个循环,以便知道它的员工。获取经理 = 名称的位置 您可以做的是执行一个 HQL 请求以获取列表中的所有员工“获取经理在(经理列表)中的位置”。它应该会大大减少花费的时间,因为您将递归地执行 15 个请求,而不是为大老板执行 13k 个请求。

Request 1    Request 2   Request 3 ...
manager   --> manager --> manager --> manager --> employee
          --> manager --> employee
          --> manager --> manager --> manager --> employee
          --> employee

否则,如果你想使用 SQL 语句,你可以考虑使用关键字 WITH。

【讨论】:

  • 是的,延迟来自许多循环(例如,一个经理可以有 20 个子经理)
  • 然后,不是获取每个经理的员工,而是获取同一层级的每个经理的所有员工。它只会改变你的请求,你不能做更少的修改。 ;)
  • 是的,如果我使用“IN”运算符,那么这应该会减少立即拨打的电话数量。我现在就试试这个,看看这是否能大大提高性能
  • 抱歉,我之前将其标记为正确...我对我的代码做了一些其他更改,但使用 IN 子句是性能的最大提升...干杯
【解决方案2】:

this similar question

另请参阅 this presentation Bill Karwin 关于数据库反模式的文章。从幻灯片 48 开始讨论“朴素树”反模式。

解决方案 #1:路径枚举。 存储祖先的路径(在您的情况下为经理):

ID, PATH, NAME
1, 1/, george
2, 2/, peter
3, 1/3, harry
4, 1/3/4, bertrand

轻松查询乔治的后代:

SELECT * from Employee WHERE path LIKE '1/%';

演示文稿还提到了我认为对您的情况不太有用的其他解决方案:

  • 解决方案 #2:嵌套集
  • 解决方案 #3:闭包表

编辑:这是将两个数据库查询与递归内存搜索混合在一起的另一个想法。

    public static class Employee {
        private Long id;
        private boolean isManager;
        private Employee manager;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public boolean isManager() {
            return isManager;
        }

        public void setIsManager(boolean isManager) {
            this.isManager = isManager;
        }

        public Employee getManager() {
            return manager;
        }

        public void setManager(Employee manager) {
            this.manager = manager;
        }
    }

首先获取数据库中的所有管理器。如果员工总数是 16k,那么经理的数量应该是可控的(没有双关语)。

    // gets all existing managers from the database
    private static List<Employee> getAllManagers() {
        //  SELECT * FROM Employee WHERE isManager = true;
        return new ArrayList<>();
    }

然后遍历所有管理器,递归确定哪些管理器在查询管理器下工作。

    private static Set<Employee> findSubordinateManagers(Employee queryManager) {
        List<Employee> allManagers = getAllManagers();
        Set<Employee> subordinateManagers = new HashSet<>();
        for (Employee employee : allManagers) {
            if (isSubordinateTo(employee, queryManager)) {
                subordinateManagers.add(employee);
            }
        }
        return subordinateManagers;
    }    

    // determines if the given employee is subordinate to the given manager
    private static boolean isSubordinateTo(Employee employee, Employee manager) {
        if (employee.getManager() == null) {
            return false;
        }
        if (employee.getManager().getId().equals(manager.getId())) {
            return true;
        }
        return isSubordinateTo(employee, employee.getManager());
    }

然后进行第二次 SQL 查询以获取所有员工直接由一组选定的经理管理:

    // finds all employees directly subordinate to the given set of managers
    private static Set<Employee> findEmployees(Set<Employee> managers) {
        // SELECT * from Employee WHERE manager IN (managers);
        return new HashSet<>();
    }    

【讨论】:

  • 在本书中,每个解决方案都与在数据库中使用正确的设计有关,而他并不想改变。还有 13k 条记录,最大深度为 20,他真的不需要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-11
  • 1970-01-01
相关资源
最近更新 更多