Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/82.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 帮助改进此SQL联合查询_Mysql_Sql - Fatal编程技术网

Mysql 帮助改进此SQL联合查询

Mysql 帮助改进此SQL联合查询,mysql,sql,Mysql,Sql,好的,我有一个访问控制列表系统,它模仿NT DACL。基本上,我有用户、组、它们之间的成员映射,还有ACL,其中有任意数量的ACE引用用户或组 例如,这允许市场营销部门组访问某些内容,但在市场营销部门工作的Joe是一个有问题的孩子,因此您可以拒绝他访问该内容,他将被拒绝,但组中的所有其他人都将被允许 我需要列举一个由给定ACL控制的对象列表——在本例中,受控对象是用户对象本身。例如,假设uid=1的用户Bob想要从系统中删除另一个用户,我想要一个用户列表来显示Bob可以在哪些用户上执行该操作。如

好的,我有一个访问控制列表系统,它模仿NT DACL。基本上,我有用户、组、它们之间的成员映射,还有ACL,其中有任意数量的ACE引用用户或组

例如,这允许市场营销部门组访问某些内容,但在市场营销部门工作的Joe是一个有问题的孩子,因此您可以拒绝他访问该内容,他将被拒绝,但组中的所有其他人都将被允许

我需要列举一个由给定ACL控制的对象列表——在本例中,受控对象是用户对象本身。例如,假设uid=1的用户Bob想要从系统中删除另一个用户,我想要一个用户列表来显示Bob可以在哪些用户上执行该操作。如果此处由WHERE usr.id=1表示的用户1将被嵌入其中的PHP应用程序缓存,并且可以访问给定的对象,我想显示它,如果她没有,那么结果集中就不应该存在它

以下是我迄今为止提出的最好的建议:

SELECT `acelist`.id, `acelist`.first_name, `acelist`.last_name, `acelist`.acl
FROM
(
  (
    SELECT `usResult`.id, `usResult`.first_name, `usResult`.last_name, `usResult`.acl, `ace`.`allowed`
    FROM `user` usResult
    INNER JOIN access_control_list acl ON usResult.acl = acl.id
    INNER JOIN group_access_control_entry ace ON acl.id = ace.acl
    INNER JOIN `group` gp ON ace.gid = gp.id
    INNER JOIN group_membership ON gp.id = group_membership.gid
    INNER JOIN `user` usr ON group_membership.uid = usr.id
    WHERE usr.id = 1
  )
  UNION ALL
  (
    SELECT `usResult`.id, `usResult`.first_name, `usResult`.last_name, `usResult`.acl, `ace`.`allowed`
    FROM `user` usResult
    INNER JOIN access_control_list acl ON usResult.acl = acl.id
    INNER JOIN user_access_control_entry ace ON acl.id = ace.acl
    INNER JOIN `user` usr ON ace.uid = usr.id
    WHERE usr.id = 1
  )
) AS acelist
GROUP BY `acelist`.id
HAVING COUNT(acelist.allowed) = SUM(acelist.allowed)
这是我正在使用的模式:

# Generated by Propel ORM
# This is a fix for InnoDB in MySQL >= 4.1.x
# It "suspends judgement" for fkey relationships until are tables are set.
SET FOREIGN_KEY_CHECKS = 0;

-- ---------------------------------------------------------------------
-- user
-- ---------------------------------------------------------------------

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user`
(
    `id` INTEGER NOT NULL,
    `first_name` VARCHAR(255) NOT NULL,
    `last_name` VARCHAR(255) NOT NULL,
    `direct_login` INTEGER,
    `acl` INTEGER NOT NULL,
    PRIMARY KEY (`id`),
    INDEX `user_FI_1` (`acl`),
    CONSTRAINT `user_FK_1`
        FOREIGN KEY (`acl`)
        REFERENCES `access_control_list` (`id`)
) ENGINE=InnoDB;

-- ---------------------------------------------------------------------
-- case_id_user
-- ---------------------------------------------------------------------

DROP TABLE IF EXISTS `case_id_user`;

CREATE TABLE `case_id_user`
(
    `uid` INTEGER NOT NULL,
    `case_id` VARCHAR(8),
    PRIMARY KEY (`uid`),
    UNIQUE INDEX `case_id_user_U_1` (`case_id`),
    CONSTRAINT `case_id_user_FK_1`
        FOREIGN KEY (`uid`)
        REFERENCES `user` (`id`)
        ON UPDATE CASCADE
        ON DELETE CASCADE
) ENGINE=InnoDB;

-- ---------------------------------------------------------------------
-- direct_login_user
-- ---------------------------------------------------------------------

DROP TABLE IF EXISTS `direct_login_user`;

CREATE TABLE `direct_login_user`
(
    `uid` INTEGER NOT NULL,
    `passhash` CHAR(60) NOT NULL,
    `email` VARCHAR(255) NOT NULL,
    `user_name` VARCHAR(45) NOT NULL,
    PRIMARY KEY (`uid`),
    UNIQUE INDEX `direct_login_user_U_1` (`user_name`),
    CONSTRAINT `direct_login_user_FK_1`
        FOREIGN KEY (`uid`)
        REFERENCES `user` (`id`)
        ON UPDATE CASCADE
        ON DELETE CASCADE
) ENGINE=InnoDB;

-- ---------------------------------------------------------------------
-- group
-- ---------------------------------------------------------------------

DROP TABLE IF EXISTS `group`;

CREATE TABLE `group`
(
    `id` INTEGER NOT NULL,
    `name` VARCHAR(45) NOT NULL,
    `description` TEXT NOT NULL,
    `acl` INTEGER NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `group_U_1` (`name`),
    INDEX `group_FI_1` (`acl`),
    CONSTRAINT `group_FK_1`
        FOREIGN KEY (`acl`)
        REFERENCES `access_control_list` (`id`)
) ENGINE=InnoDB;

-- ---------------------------------------------------------------------
-- privilege
-- ---------------------------------------------------------------------

DROP TABLE IF EXISTS `privilege`;

CREATE TABLE `privilege`
(
    `id` INTEGER NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(45) NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `privilege_U_1` (`name`)
) ENGINE=InnoDB;

-- ---------------------------------------------------------------------
-- access_control_list
-- ---------------------------------------------------------------------

DROP TABLE IF EXISTS `access_control_list`;

CREATE TABLE `access_control_list`
(
    `id` INTEGER NOT NULL AUTO_INCREMENT,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB;

-- ---------------------------------------------------------------------
-- user_access_control_entry
-- ---------------------------------------------------------------------

DROP TABLE IF EXISTS `user_access_control_entry`;

CREATE TABLE `user_access_control_entry`
(
    `acl` INTEGER NOT NULL,
    `uid` INTEGER NOT NULL,
    `privilege_id` INTEGER NOT NULL,
    `allowed` TINYINT NOT NULL,
    PRIMARY KEY (`acl`,`uid`,`privilege_id`,`allowed`),
    INDEX `user_access_control_entry_FI_1` (`privilege_id`),
    INDEX `user_access_control_entry_FI_2` (`uid`),
    CONSTRAINT `user_access_control_entry_FK_1`
        FOREIGN KEY (`privilege_id`)
        REFERENCES `privilege` (`id`)
        ON UPDATE CASCADE
        ON DELETE CASCADE,
    CONSTRAINT `user_access_control_entry_FK_2`
        FOREIGN KEY (`uid`)
        REFERENCES `user` (`id`)
        ON UPDATE RESTRICT
        ON DELETE CASCADE,
    CONSTRAINT `user_access_control_entry_FK_3`
        FOREIGN KEY (`acl`)
        REFERENCES `access_control_list` (`id`)
        ON UPDATE RESTRICT
        ON DELETE CASCADE
) ENGINE=InnoDB;

-- ---------------------------------------------------------------------
-- group_access_control_entry
-- ---------------------------------------------------------------------

DROP TABLE IF EXISTS `group_access_control_entry`;

CREATE TABLE `group_access_control_entry`
(
    `acl` INTEGER NOT NULL,
    `gid` INTEGER NOT NULL,
    `privilege_id` INTEGER NOT NULL,
    `allowed` TINYINT NOT NULL,
    PRIMARY KEY (`acl`,`gid`,`privilege_id`,`allowed`),
    INDEX `group_access_control_entry_FI_1` (`privilege_id`),
    INDEX `group_access_control_entry_FI_2` (`gid`),
    CONSTRAINT `group_access_control_entry_FK_1`
        FOREIGN KEY (`privilege_id`)
        REFERENCES `privilege` (`id`)
        ON UPDATE CASCADE
        ON DELETE CASCADE,
    CONSTRAINT `group_access_control_entry_FK_2`
        FOREIGN KEY (`gid`)
        REFERENCES `group` (`id`)
        ON UPDATE RESTRICT
        ON DELETE CASCADE,
    CONSTRAINT `group_access_control_entry_FK_3`
        FOREIGN KEY (`acl`)
        REFERENCES `access_control_list` (`id`)
        ON UPDATE RESTRICT
        ON DELETE CASCADE
) ENGINE=InnoDB;

-- ---------------------------------------------------------------------
-- group_membership
-- ---------------------------------------------------------------------

DROP TABLE IF EXISTS `group_membership`;

CREATE TABLE `group_membership`
(
    `uid` INTEGER NOT NULL,
    `gid` INTEGER NOT NULL,
    PRIMARY KEY (`uid`,`gid`),
    INDEX `group_membership_FI_2` (`gid`),
    CONSTRAINT `group_membership_FK_1`
        FOREIGN KEY (`uid`)
        REFERENCES `user` (`id`)
        ON UPDATE RESTRICT
        ON DELETE CASCADE,
    CONSTRAINT `group_membership_FK_2`
        FOREIGN KEY (`gid`)
        REFERENCES `group` (`id`)
        ON UPDATE RESTRICT
        ON DELETE CASCADE
) ENGINE=InnoDB;

# This restores the fkey checks, after having unset them earlier
SET FOREIGN_KEY_CHECKS = 1;
这里的任何一位SQL专家都看到我可以做些什么来简化查询,或者让查询执行得更快吗


编辑:理想情况下,我能够以某种方式为任何ACL对象完成这项复杂的工作,这样我就可以避免为数据库中的每个ACL对象编写这样的查询……

当然不是更漂亮,但可能更快,因为要处理的数据更少

SELECT  `acelist`.id, `acelist`.first_name, `acelist`.last_name, `acelist`.acl 
FROM    `usResult` acl
        INNER JOIN (
          SELECT  `usResult`.id
          FROM    (      
                    SELECT  `usResult`.id
                             , SUM(`ace`.`allowed`) AS SumAllowed
                             , COUNT(`ace`.`allowed`) AS CountAllowed
                    FROM    `user` usResult
                            INNER JOIN access_control_list acl ON usResult.acl = acl.id
                            INNER JOIN group_access_control_entry ace ON acl.id = ace.acl
                            INNER JOIN `group` gp ON ace.gid = gp.id
                            INNER JOIN group_membership ON gp.id = group_membership.gid
                            INNER JOIN `user` usr ON group_membership.uid = usr.id
                    WHERE   usr.id = 1
                    GROUP BY
                            `usResult`.id
                    UNION ALL 
                    SELECT  `usResult`.id
                             , SUM(`ace`.`allowed`) AS SumAllowed
                             , COUNT(`ace`.`allowed`) AS CountAllowed
                    FROM    `user` usResult
                            INNER JOIN access_control_list acl ON usResult.acl = acl.id
                            INNER JOIN user_access_control_entry ace ON acl.id = ace.acl
                            INNER JOIN `user` usr ON ace.uid = usr.id
                    WHERE usr.id = 1
                    GROUP BY
                            `usResult`.id
                  ) results
          GROUP BY
                  results.id
          HAVING  SUM(results.SumAllowed) = SUM(results.CountAllowed)
      ) r ON r.id = acl.id

当然不是更漂亮,但可能更快,因为需要处理的数据更少

SELECT  `acelist`.id, `acelist`.first_name, `acelist`.last_name, `acelist`.acl 
FROM    `usResult` acl
        INNER JOIN (
          SELECT  `usResult`.id
          FROM    (      
                    SELECT  `usResult`.id
                             , SUM(`ace`.`allowed`) AS SumAllowed
                             , COUNT(`ace`.`allowed`) AS CountAllowed
                    FROM    `user` usResult
                            INNER JOIN access_control_list acl ON usResult.acl = acl.id
                            INNER JOIN group_access_control_entry ace ON acl.id = ace.acl
                            INNER JOIN `group` gp ON ace.gid = gp.id
                            INNER JOIN group_membership ON gp.id = group_membership.gid
                            INNER JOIN `user` usr ON group_membership.uid = usr.id
                    WHERE   usr.id = 1
                    GROUP BY
                            `usResult`.id
                    UNION ALL 
                    SELECT  `usResult`.id
                             , SUM(`ace`.`allowed`) AS SumAllowed
                             , COUNT(`ace`.`allowed`) AS CountAllowed
                    FROM    `user` usResult
                            INNER JOIN access_control_list acl ON usResult.acl = acl.id
                            INNER JOIN user_access_control_entry ace ON acl.id = ace.acl
                            INNER JOIN `user` usr ON ace.uid = usr.id
                    WHERE usr.id = 1
                    GROUP BY
                            `usResult`.id
                  ) results
          GROUP BY
                  results.id
          HAVING  SUM(results.SumAllowed) = SUM(results.CountAllowed)
      ) r ON r.id = acl.id

根据用户的数量和授权动作的频率,您可能需要考虑为特定用户缓存整个权限子树。

您可以通过跟踪权限表上次更新的时间来坚持使用ACID缓存,这将为您提供一个快速查询,可以检测是否需要运行较慢的查询


否则你看起来很好;我不喜欢COUNTallowed=sumlowed来确定没有零。与必须计算所有记录的计数和总和的方法相比,NOT EXIST变量应该能够进行优化。但是,假设合理的数据分布,我期望更大的Win因子来缓存权限。

根据用户的数量和授权动作的频率,您可能需要考虑为特定用户缓存整个权限子树。 您可以通过跟踪权限表上次更新的时间来坚持使用ACID缓存,这将为您提供一个快速查询,可以检测是否需要运行较慢的查询


否则你看起来很好;我不喜欢COUNTallowed=sumlowed来确定没有零。与必须计算所有记录的计数和总和的方法相比,NOT EXIST变量应该能够进行优化。但是,假设数据分布正常,我希望缓存权限的赢家因素会大得多。

什么不存在?我不熟悉这个!我仔细阅读了您的查询,我在这里匆匆忙忙,然后您试图检测特定结果用户id下是否不允许有零?所以,如果这仍然是真的,那么重写选择id从。。。如果不存在,请从中选择id。。。其中outter.id=inner.id和inner.allowed=0相关子查询将在看到第一个0时立即退出。实际上,需要在典型的数据分布上进行测试,并使用索引。不存在什么变体?我不熟悉这个!我仔细阅读了您的查询,我在这里匆匆忙忙,然后您试图检测特定结果用户id下是否不允许有零?所以,如果这仍然是真的,那么重写选择id从。。。如果不存在,请从中选择id。。。其中outter.id=inner.id和inner.allowed=0相关子查询将在看到第一个0时立即退出。实际上,我们需要在典型的数据分布上进行测试,还需要使用索引。。这也很好,因为它概括了-一个人可以将它用于另一个ACL控制对象,即计算机,它的修改更少。@Billy,你要杀了我。。。更快吗?列文:我不知道。我没有足够大的可用数据集-我的查询和这个查询都不到0.001秒。噢。。这也很好,因为它概括了-一个人可以将它用于另一个ACL控制对象,即计算机,它的修改更少。@Billy,你要杀了我。。。更快吗?列文:我不知道。我没有足够大的可用数据集-我的查询和这个查询都需要不到0.001秒的时间。