当我接受@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秒钟 - 并且我无法修改的限制。如果我写:
WHERE @slide_num >= 10 AND @slide_num <= 15
我得到一个空的结果(当然,我已经检查过有足够的幻灯片)。
我无法理解为什么需要3秒才能获得200行。
我需要能够以最快的方式查询所选范围之间的幻灯片,这些幻灯片是动态的。
如果您发现缺少某些内容,请注释它是什么,以便发布。
谢谢。
正如@strawberry建议的那样,我尝试应用他的方法。但是,查询的响应时间与写BETWEEN 0 AND 5
的范围相同,而不是写BETWEEN 0 AND 200
(大约17秒)。
由于这可能是由于索引编制错误,我决定在此处编写EXPLAIN
,因为我看不到任何错误的索引(WHERE
子句中的每个条件都有它的索引)。
答案 0 :(得分:0)
考虑这个简化的例子......
DROP TABLE IF EXISTS slides;
CREATE TABLE slides
(slide_id INT NOT NULL);
INSERT INTO slides VALUES
(1),
(2),
(4),
(5),
(6),
(7);
DROP TABLE IF EXISTS slides_tags;
CREATE TABLE slides_tags
(slide_id INT NOT NULL
,tag_id INT NOT NULL
,PRIMARY KEY(slide_id,tag_id)
);
INSERT INTO slides_tags VALUES
(1,101),
(1,103),
(1,105),
(1,107),
(2,102),
(2,104),
(2,106),
(2,108),
(4,105),
(4,110),
(5,101);
SELECT slide_id
, tag_id
, i
FROM
( SELECT s.*
, st.tag_id
, CASE WHEN @prev = s.slide_id THEN @i:=@i ELSE @i:=@i+1 END i
, @prev:=s.slide_id
FROM slides s
LEFT
JOIN slides_tags st
ON st.slide_id = s.slide_id
JOIN
( SELECT @prev:=null,@i:=0) vars
ORDER
BY s.slide_id
) x
WHERE i BETWEEN 3 AND 5;
+----------+--------+------+
| slide_id | tag_id | i |
+----------+--------+------+
| 4 | 105 | 3 |
| 4 | 110 | 3 |
| 5 | 101 | 4 |
| 6 | NULL | 5 |
+----------+--------+------+
为了清晰起见,我已在结果中包含i
列。当然,如果不需要,可以从superquery中省略它。
编辑:
似乎你可以重写这个查询,但是,老实说,我为此感到困惑:
SELECT s.slide_id
, st.tag_id
, CASE WHEN @prev = s.slide_id THEN @i:=@i ELSE @i:=@i+1 END i
, @prev:=s.slide_id
FROM (SELECT @i:=0, @prev := 0) vars
JOIN slides s
LEFT
JOIN slides_tags st
ON st.slide_id = s.slide_id
HAVING i BETWEEN 3 AND 5
ORDER
BY slide_id
, tag_id;
+----------+--------+------+-------------------+
| slide_id | tag_id | i | @prev:=s.slide_id |
+----------+--------+------+-------------------+
| 4 | 105 | 3 | 4 |
| 4 | 110 | 3 | 4 |
| 5 | 101 | 4 | 5 |
| 6 | NULL | 5 | 6 |
+----------+--------+------+-------------------+