У меня есть следующий запрос. Идея в том, что она позволяет мне знать, что groups
, а затем users
, имеют доступ к каждому component_instance
. Я интересно, если есть лучший способ сделать это, как запрос является довольно медленным, но это очень удобно, чтобы эти дополнительные колонки каждый раз, когда я имею дело с этой таблицей:Сделать запрос GROUP_CONCAT более эффективным
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
таблица разрешений, как так (простите рельсам!):
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
типы разрешений являются edit
и view
. Группе может быть присвоена одна или обе. Разрешения также рекурсивные в том смысле, что если нет групповых разрешений на component_instance
, нам нужно будет проверить его предков, чтобы найти первое, где установлены разрешения (если они есть). Это делает вопрос с одним вопросом весьма важным, потому что я могу затем объединить этот запрос с логикой выбора, которую обеспечивает драгоценный камень ancestry
(материализованное дерево путей).
Update
Я с тех пор нашел этот запрос тесты быстрее:
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
Вот EXPLAIN для приведенного выше запроса и таблицы 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
ORDER BY
исходит из ancestry gem, но если есть лучший способ сделать это, я был бы рад субмину t это как запрос тянуть к ним.
В любом случае, если бы я был вами, я бы разделил каждое свое обновление, используя строку 'UPDATE', и сохранил все содержимое в вопросе. Это делает его более понятным для чтения. – Mehran
Спасибо, Мехран, я обновил это. Сначала я решил ответить на свой вопрос, а затем подумал, чтобы сделать щедрость. –
Также я думаю, что если вы используете 2-ю версию, вы можете опустить последние два соединения и использовать view_groups_users.user_id и edit_groups_users.user_id в group_concat – maraca