Ich habe die folgende Abfrage. Die Idee ist, dass es mir erlaubt zu wissen, was groups
und anschließend users
Zugang zu jedem component_instance
haben. Ich frage mich, ob es ein besserer Weg, dies als die Abfrage zu tun ist ziemlich langsam, aber es ist wirklich praktisch, diese zusätzliche Spalten jedes Mal, wenn ich mit dieser Tabelle tun hat:Eine GROUP_CONCAT Abfrage effizienter machen
SELECT component_instances.*,
GROUP_CONCAT(DISTINCT IF(permissions.view, groups.id, NULL)) AS view_group_ids,
GROUP_CONCAT(DISTINCT IF(permissions.edit, groups.id, NULL)) AS edit_group_ids,
GROUP_CONCAT(DISTINCT IF(permissions.view, users.id, NULL)) AS view_user_ids,
GROUP_CONCAT(DISTINCT IF(permissions.edit, users.id, NULL)) AS edit_user_ids
FROM `component_instances`
LEFT OUTER JOIN permissions ON permissions.component_instance_id = component_instances.id
LEFT OUTER JOIN groups ON groups.id = permissions.group_id
LEFT OUTER JOIN groups_users ON groups_users.group_id = groups.id
LEFT OUTER JOIN users ON users.id = groups_users.user_id
GROUP BY component_instances.id
ORDER BY (case when component_instances.ancestry is null then 0 else 1 end), component_instances.ancestry, position
Die Berechtigungstabelle wie so ist (entschuldigen Sie die Rails!):
create_table "permissions", :force => true do |t|
t.integer "component_instance_id"
t.integer "group_id"
t.boolean "view", :default => false
t.boolean "edit", :default => false
end
die Arten von Berechtigungen sind edit
und view
. Eine Gruppe kann entweder einem oder beiden zugewiesen werden. Berechtigungen sind auch rekursiv, wenn wir keine Gruppenberechtigungen für eine component_instance
haben, müssen wir ihre Vorfahren überprüfen, um die ersten zu finden, bei denen Berechtigungen gesetzt sind (falls vorhanden). Dies macht es sehr wichtig, die eine Abfrage zu haben, da ich diese Abfrage dann mit der Auswahllogik kombinieren kann, die der Edelstein ancestry
bereitstellt (materialisierter Pfadbaum).
aktualisieren
Ich habe schneller, da diese Abfrage Benchmarks gefunden:
SELECT component_instances.*,
GROUP_CONCAT(DISTINCT view_groups.id) AS view_group_ids,
GROUP_CONCAT(DISTINCT edit_groups.id) AS edit_group_ids,
GROUP_CONCAT(DISTINCT view_users.id) AS view_user_ids,
GROUP_CONCAT(DISTINCT edit_users.id) AS edit_user_ids
FROM `component_instances`
LEFT OUTER JOIN permissions ON permissions.component_instance_id = component_instances.id
LEFT OUTER JOIN groups view_groups ON view_groups.id = permissions.group_id AND permissions.view = 1
LEFT OUTER JOIN groups edit_groups ON edit_groups.id = permissions.group_id AND permissions.edit = 1
LEFT OUTER JOIN groups_users view_groups_users ON view_groups_users.group_id = view_groups.id
LEFT OUTER JOIN groups_users edit_groups_users ON edit_groups_users.group_id = edit_groups.id
LEFT OUTER JOIN users view_users ON view_users.id = view_groups_users.user_id
LEFT OUTER JOIN users edit_users ON edit_users.id = edit_groups_users.user_id
GROUP BY component_instances.id
ORDER BY (case when component_instances.ancestry is null then 0 else 1 end), component_instances.ancestry, position
Hier ist ein für die Abfrage über EXPLAIN ist und die Tabelle Anweisungen CREATE:
+----+-------------+---------------------+--------+-----------------------------------------------+--------------------------------------------+---------+--------------------------------------------+------+------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------------+--------+-----------------------------------------------+--------------------------------------------+---------+--------------------------------------------+------+------------------------------------------------------+
| 1 | SIMPLE | component_instances | ALL | PRIMARY,index_component_instances_on_ancestry | NULL | NULL | NULL | 119 | "Using temporary; Using filesort" |
| 1 | SIMPLE | permissions | ALL | NULL | NULL | NULL | NULL | 6 | "Using where; Using join buffer (Block Nested Loop)" |
| 1 | SIMPLE | view_groups | eq_ref | PRIMARY | PRIMARY | 4 | 05707d890df9347c.permissions.group_id | 1 | "Using where; Using index" |
| 1 | SIMPLE | edit_groups | eq_ref | PRIMARY | PRIMARY | 4 | 05707d890df9347c.permissions.group_id | 1 | "Using where; Using index" |
| 1 | SIMPLE | view_groups_users | ref | index_groups_users_on_group_id_and_user_id | index_groups_users_on_group_id_and_user_id | 5 | 05707d890df9347c.view_groups.id | 1 | "Using index" |
| 1 | SIMPLE | edit_groups_users | ref | index_groups_users_on_group_id_and_user_id | index_groups_users_on_group_id_and_user_id | 5 | 05707d890df9347c.edit_groups.id | 1 | "Using index" |
| 1 | SIMPLE | view_users | eq_ref | PRIMARY | PRIMARY | 4 | 05707d890df9347c.view_groups_users.user_id | 1 | "Using index" |
| 1 | SIMPLE | edit_users | eq_ref | PRIMARY | PRIMARY | 4 | 05707d890df9347c.edit_groups_users.user_id | 1 | "Using index" |
+----+-------------+---------------------+--------+-----------------------------------------------+--------------------------------------------+---------+--------------------------------------------+------+------------------------------------------------------+
CREATE TABLE `component_instances` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`visible` int(11) DEFAULT '1',
`instance_id` int(11) DEFAULT NULL,
`deleted_on` date DEFAULT NULL,
`instance_type` varchar(255) DEFAULT NULL,
`component_id` int(11) DEFAULT NULL,
`deleted_root_item` int(11) DEFAULT NULL,
`locked_until` datetime DEFAULT NULL,
`theme_id` int(11) DEFAULT NULL,
`position` int(11) DEFAULT NULL,
`ancestry` varchar(255) DEFAULT NULL,
`ancestry_depth` int(11) DEFAULT '0',
`cached_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_component_instances_on_ancestry` (`ancestry`)
) ENGINE=InnoDB AUTO_INCREMENT=121 DEFAULT CHARSET=utf8
CREATE TABLE `groups` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
CREATE TABLE `groups_users` (
`group_id` int(11) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
KEY `index_groups_users_on_group_id_and_user_id` (`group_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
CREATE TABLE `permissions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`component_instance_id` int(11) DEFAULT NULL,
`group_id` int(11) DEFAULT NULL,
`view` tinyint(1) DEFAULT '0',
`edit` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `edit_permissions_index` (`edit`,`group_id`,`component_instance_id`),
KEY `view_permissions_index` (`view`,`group_id`,`component_instance_id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`real_name` varchar(255) DEFAULT NULL,
`username` varchar(255) NOT NULL DEFAULT '',
`email` varchar(255) NOT NULL DEFAULT '',
`crypted_password` varchar(255) DEFAULT NULL,
`administrator` int(11) NOT NULL DEFAULT '0',
`password_salt` varchar(255) DEFAULT NULL,
`remember_token_expires` datetime DEFAULT NULL,
`persistence_token` varchar(255) DEFAULT NULL,
`disabled` tinyint(1) DEFAULT NULL,
`time_zone` varchar(255) DEFAULT NULL,
`login_count` int(11) DEFAULT NULL,
`failed_login_count` int(11) DEFAULT NULL,
`last_request_at` datetime DEFAULT NULL,
`current_login_at` datetime DEFAULT NULL,
`last_login_at` datetime DEFAULT NULL,
`current_login_ip` varchar(255) DEFAULT NULL,
`last_login_ip` varchar(255) DEFAULT NULL,
`perishable_token` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `index_users_on_username` (`username`),
KEY `index_users_on_perishable_token` (`perishable_token`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8
Die ORDER BY
kommt von der ancestry gem aber wenn es eine bessere Möglichkeit gibt, dies zu tun, würde ich glücklich sein, submi t das als Pull-Anfrage an sie.
Es ist üblich, all Ihren Text in der Frage zu halten, wenn ich Sie wäre, würde ich jedes Update mit einer 'UPDATE'-Zeile trennen und den Stamm im Frageteil behalten. Es macht es viel klarer zu lesen. – Mehran
Danke Mehran, ich habe das aktualisiert. Ich ging zuerst meine eigene Frage zu beantworten, dann dachte ich, eine Prämie zu tun. –
Auch ich denke, wenn Sie die zweite Version verwenden, können Sie die letzten zwei Joins weglassen und verwenden Sie view_groups_users.user_id und edit_groups_users.user_id in der group_concat – maraca