解决方案 B
因为我接受了@Strawberry 的回答,并且这个解决方案不属于帖子本身的问题,所以我不会把它写成答案,而是把它留给任何可能对它有用的人。
主要问题是查询性能和结构问题。我正在搜索所有人的所有属性,slides
然后限制结果的事实使它变得如此缓慢。解决方案是首先获取我想要获取的幻灯片,然后从较短的结果集中搜索所有额外信息。
因此,最终查询(在 0.2 秒内运行并获得我希望的所有结果)将如下所示:
SELECT
sl.slide_id AS slide_id,
sl.time_in AS time_in,
sl.time_out AS time_out,
sl.duration AS duration,
sl.slide_order AS slide_order,
sl.title AS title,
sl.slide_type AS slide_type,
sl.report_id AS report_id,
sltg.tag_category_id AS tag_category_id,
sltg.tag_value_id AS tag_value_id,
sltgc.txt AS tag_category_text,
sltgv.txt AS tag_value_text,
FROM (SELECT
sl.time_in AS time_in,
sl.time_out AS time_out,
sl.duration AS duration,
sl.slide_order AS slide_order,
sl.media_id AS media_id,
sl.title AS title,
sl.slide_type AS slide_type,
slrep.report_id AS report_id,
slrep.slide_id AS slide_id
FROM er_slides sl
INNER JOIN er_slides_in_report slrep
ON slrep.slide_id = sl.unique_id
AND slrep.report_id IN (1461317308472,1461597566425,1461598458236)
AND slrep.deleted_date IS NULL
LIMIT 0, 5
) sl
INNER JOIN er_slides_tags sltg
ON sltg.deleted_date IS NULL
AND sltg.slide_id = sl.slide_id
INNER JOIN er_slide_tags_categories sltgc
ON sltgc.id = sltg.tag_category_id
INNER JOIN er_slide_tags_values sltgv
ON sltgv.id = sltg.tag_value_id
ORDER BY slide_id, tag_value_id;
如您所见,我在搜索其他内容之前限制了集合。之后,查询运行得非常快。我希望这种方法可以帮助某人改进他们自己的查询,以我原来的查询为例,说明你不能做的事情。
原来的问题
我有一张表,其中包含一些元素(幻灯片),这些元素(幻灯片)被分组在一些容器(报告)上,每个元素都有一些属性(标签值)和分配给它们的类别(标签类别)。这就像一个标记系统,其中元素 X 可以具有来自类别 Z 的标记 Y。
数据库结构
CREATE TABLE IF NOT EXISTS `er_reports` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`unique_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`name` varchar(256) COLLATE utf8_unicode_ci NOT NULL,
`user_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`author` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`report_status` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'incomplete',
`num_slides` int(4) NOT NULL DEFAULT '0',
`report_type` varchar(25) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'report',
`target_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_date` datetime DEFAULT NULL,
`uploaded_date` datetime DEFAULT NULL,
`deleted_date` datetime DEFAULT NULL,
`modified_date` datetime DEFAULT NULL,
`item_reference` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`is_favourite` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `unique_id` (`unique_id`),
KEY `unique_id_2` (`unique_id`),
KEY `unique_id_3` (`unique_id`),
KEY `user_id` (`user_id`),
KEY `deleted_date` (`deleted_date`),
KEY `is_favourite` (`is_favourite`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=714 ;
CREATE TABLE IF NOT EXISTS `er_slides` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`unique_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`report_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`action_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`media_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`thumbnail_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`media_offset` int(6) NOT NULL DEFAULT '0',
`time_in` decimal(9,3) DEFAULT NULL,
`time_out` decimal(9,3) DEFAULT NULL,
`duration` decimal(9,3) NOT NULL DEFAULT '10.000',
`title` text COLLATE utf8_unicode_ci,
`slide_comment` text COLLATE utf8_unicode_ci,
`note_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`content` text COLLATE utf8_unicode_ci,
`media_object` text COLLATE utf8_unicode_ci,
`slide_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'action',
`user_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`slide_order` int(4) NOT NULL DEFAULT '0',
`count_slide` tinyint(1) NOT NULL DEFAULT '1',
`visible` tinyint(1) NOT NULL DEFAULT '1',
`deleted_date` datetime DEFAULT NULL,
`created_date` datetime DEFAULT NULL,
`uploaded_date` datetime DEFAULT NULL,
`modified_date` datetime DEFAULT NULL,
`item_reference` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `unique_id` (`unique_id`),
KEY `report_id` (`report_id`),
KEY `deleted_date` (`deleted_date`),
KEY `action_id` (`action_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=31899 ;
CREATE TABLE IF NOT EXISTS `er_slides_in_report` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`report_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`slide_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`slide_order` int(3) NOT NULL DEFAULT '1',
`added_date` datetime DEFAULT NULL,
`modified_date` datetime DEFAULT NULL,
`deleted_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `report_id` (`report_id`,`slide_id`,`deleted_date`),
KEY `slide_order` (`slide_order`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=16843 ;
CREATE TABLE IF NOT EXISTS `er_slides_tags` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`slide_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`tag_category_id` bigint(20) NOT NULL,
`tag_value_id` bigint(20) NOT NULL,
`created_date` datetime NOT NULL,
`deleted_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `slide_id` (`slide_id`,`tag_category_id`,`tag_value_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=220623 ;
CREATE TABLE IF NOT EXISTS `er_slide_tags_categories` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`txt` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `txt` (`txt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=17 ;
CREATE TABLE IF NOT EXISTS `er_slide_tags_values` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`txt` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `txt` (`txt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=439 ;
我试过的
SELECT @slide_num := if(@sl_id = slrep.slide_id collate utf8_unicode_ci, @slide_num, @slide_num := @slide_num+1) as slide_num,
@sl_id := slrep.slide_id collate utf8_unicode_ci as sl_id,
slrep.report_id AS report_id,
slrep.slide_id AS slide_id,
sltg.tag_category_id AS tag_category_id,
sltg.tag_value_id AS tag_value_id,
sltgc.txt AS tag_category_text,
sltgv.txt AS tag_value_text,
sl.time_in AS time_in,
sl.time_out AS time_out,
sl.duration AS duration,
sl.slide_order AS slide_order,
sl.title AS title,
sl.slide_type AS slide_type
FROM (SELECT @sl_id:=1, @slide_num := 0) v, er_slides sl
INNER JOIN er_slides_in_report slrep
ON slrep.slide_id = sl.unique_id
AND slrep.report_id IN (1461317308472,1461597566425,1461598458236)
AND slrep.deleted_date IS NULL
INNER JOIN er_slides_tags sltg
ON sltg.deleted_date IS NULL
AND sltg.slide_id = sl.unique_id
INNER JOIN er_slide_tags_categories sltgc
ON sltgc.id = sltg.tag_category_id
INNER JOIN er_slide_tags_values sltgv
ON sltgv.id = sltg.tag_value_id
WHERE @slide_num >= 0 AND @slide_num <= 5
ORDER BY slide_id, tag_value_id;
我已经为您提供了一些虚假的报告 ID,以查看查询是如何构建的。
问题
问题是这还不够快——获取 5 张幻灯片、200 行的信息需要将近 3 秒——而且我无法修改from limit。如果我写:
WHERE @slide_num >= 10 AND @slide_num <= 15
我得到一个空的结果(当然,我已经检查过有足够的幻灯片)。
我也不明白为什么需要 3 秒才能获得 200 行。
我需要的
我需要能够以最快的方式仅查询所选范围之间的幻灯片,这是动态的。
如果您发现缺少某些内容,请评论它是什么,以便我可以发布它。
谢谢你。
编辑:解释查询(草莓方法)
正如@strawberry 建议的那样,我尝试应用他的方法。BETWEEN 0 AND 5
但是,查询的响应时间与写入范围的响应时间相同BETWEEN 0 AND 200
(两者都大约 17 秒)。
因为这可能是因为索引错误,所以我决定在EXPLAIN
这里写,因为我看不到任何错误的索引(放在WHERE
子句中的每个条件都有它的索引)。