0

ソリューション 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

空の結果が得られます (もちろん、十分な数のスライドがあることを確認しました)。

200行を取得するのに3秒かかる理由もわかりません。

必要なもの

可能な限り最速の方法で、選択した範囲内にあるスライドのみを動的にクエリできるようにする必要があります。

何か足りないものを見つけた場合は、投稿できるようにコメントしてください。

ありがとうございました。

編集:クエリの説明(ストロベリーアプローチ)

@strawberry が示唆したように、私は彼のアプローチを適用しようとしました。ただし、クエリの応答時間は、書き込みよりBETWEEN 0 AND 5も書き込み範囲が同じですBETWEEN 0 AND 200(両方とも約 17 秒)。

これは不適切なインデックス付けが原因である可能性があるため、不適切なインデックス付けが見られないため、ここに記述することにしました (句にEXPLAIN入れられたすべての条件にはインデックスがあります)。WHERE

私のクエリに適用された@strawberryアプローチのEXPLAIN結果

4

1 に答える 1

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わかりやすくするために、結果に列を含めました。もちろん、必要ない場合は、スーパークエリから省略してください。

編集:

このクエリを次のように書き直すことができるようですが、正直なところ、これが機能する理由については困惑しています。

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 |
+----------+--------+------+-------------------+
于 2016-04-26T13:29:06.280 に答える