MySQL选择是否所有远程儿童都符合条件

时间:2016-10-17 12:13:18

标签: mysql sql ruby-on-rails ruby

Reduced database schema

我有一个关于(至少对我来说)复杂的SQL语句的问题。给定interface我想找到所有access_lists,可以在interface上使用。我正在创建一个Ruby on Rails应用程序,该任务的工作Ruby代码如下(应该是非常明显的):

class Interface < ActiveRecord::Base

  def valid_access_lists
    # find all valid networks (.ip() converts object into manageable IP object)
    valid_networks = self.routes.map { |route| route.network.ip() }
    return AccessList.includes(access_list_elements: [{ rule: [:ip_from] }]).all().select do |acl|
      # all rule.ip_froms are in valid networks?
      acl.access_list_elements.all? do |acle|
        # current rule.ip_from is in any of the valid networks?
        valid_networks.any? { |network| network.include?(acle.rule.ip_from.ip()) }
      end
    end
  end

end

问题在于,它(正如预期的那样)超级慢(是的,includes阻止了N + 1个查询)。 我解决此问题的方法是编写一个SQL语句,该语句执行valid_access_lists一次执行的所有操作。

以下语句将valid_networks作为((network_addr1, broadcast_addr1), (network_addr2, broadcast_addr2), ...)。这里有一个问题:它只考虑IPv4地址(当使用逻辑OR计算广播地址时可以在第2行看到)。如果ips中的记录是IPv4,ips.ip_high IS NULL,则两列都是NOT NULL。通过执行(ip_high << 64) + ip_low构建IPv6地址。 计算网络和广播地址的想法是使用ips运算符检查rules的{​​{1}}。

BETWEEN

此语句连接表以启用基于SELECT coalesce(nw_ips.`ip_high` << 64, 0) + nw_ips.`ip_low` AS nw_addr, (coalesce(nw_ips.`ip_high` << 64, 0) + nw_ips.`ip_low`) | ((1 << (32 - nw_ips.`prefix`)) - 1) AS bc_addr FROM `ips` nw_ips LEFT JOIN `routes` ON nw_ips.`id` = `routes`.`ip_network_id` LEFT JOIN `interfaces` ON `routes`.`interface_id` = `interfaces`.`id` WHERE `interfaces`.`id` = 1

检查rules
access_lists

这里的主要问题是,我需要按SELECT `access_lists`.* FROM `access_lists` LEFT JOIN `access_list_elements` ON `access_lists`.`id` = `access_list_elements`.`access_list_id` LEFT JOIN `rules` ON `access_list_elements`.`rule_id` = `rules`.`id` LEFT JOIN `ips` ON `rules`.`ip_from_id` = `ips`.`id` WHERE ... rules(及其各自的ips)进行分组,以便检查access_list中是否rules {1}}至少包含在access_list以及我被卡住的地方。

0 个答案:

没有答案