2017-02-05 9 views
0

私は500000+の行を持つメインテーブルを持っています。MySQLはJOINクエリでインデックスを使用しません

CREATE TABLE `esc_questions`(
    `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `esc_id` INT(11) NOT NULL, 
    `question_text` LONGTEXT COLLATE utf8_unicode_ci NOT NULL, 
    `answer_1` TEXT COLLATE utf8_unicode_ci NOT NULL, 
    `answer_2` TEXT COLLATE utf8_unicode_ci NOT NULL, 
    `answer_3` TEXT COLLATE utf8_unicode_ci NOT NULL, 
    `answer_4` TEXT COLLATE utf8_unicode_ci NOT NULL, 
    `answer_5` TEXT COLLATE utf8_unicode_ci NOT NULL, 
    `right_answer` VARCHAR(255) COLLATE utf8_unicode_ci NOT NULL, 
    `disciplinas_id` INT(11) UNSIGNED NOT NULL, 
    `assunto_id` INT(11) UNSIGNED NOT NULL, 
    `orgao_id` INT(11) UNSIGNED NOT NULL, 
    `cargo_id` INT(11) UNSIGNED NOT NULL, 
    `ano` INT(11) NOT NULL, 
    `banca_id` INT(11) UNSIGNED NOT NULL, 
    `question_type` TINYINT(4) NOT NULL, 
    `url` TEXT COLLATE utf8_unicode_ci NOT NULL, 
    `created_at` TIMESTAMP NULL DEFAULT NULL, 
    `updated_at` TIMESTAMP NULL DEFAULT NULL, 
    PRIMARY KEY(`id`), 
    KEY `idx_ano`(`ano`) USING BTREE, 
    KEY `idx_question_type`(`question_type`) USING BTREE, 
    KEY `idx_cargo_id`(`cargo_id`) USING BTREE, 
    KEY `idx_orgao_id`(`orgao_id`) USING BTREE, 
    KEY `idx_banca_id`(`banca_id`) USING BTREE, 
    KEY `idx_question_id`(`id`) USING BTREE, 
    KEY `idx_assunto_id`(`assunto_id`) USING BTREE, 
    KEY `idx_disciplinas_id`(`disciplinas_id`) USING BTREE, 
    CONSTRAINT `fk_assunto_id` FOREIGN KEY(`assunto_id`) REFERENCES `esc_assunto`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 
    CONSTRAINT `fk_banca_id` FOREIGN KEY(`banca_id`) REFERENCES `esc_bancas`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 
    CONSTRAINT `fk_cargo_id` FOREIGN KEY(`cargo_id`) REFERENCES `esc_cargo`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 
    CONSTRAINT `fk_disciplinas_id` FOREIGN KEY(`disciplinas_id`) REFERENCES `esc_disciplinas`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 
    CONSTRAINT `fk_orgao_id` FOREIGN KEY(`orgao_id`) REFERENCES `esc_orgao`(`id`) ON DELETE NO ACTION ON UPDATE NO ACTION 
) ENGINE = INNODB AUTO_INCREMENT = 516157 DEFAULT CHARSET = utf8 COLLATE = utf8_unicode_ci 


関連データは、この1と非常によく似て5つの追加のテーブルに格納されます。

CREATE TABLE `esc_assunto`(
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, 
`name` VARCHAR(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
PRIMARY KEY(`id`), 
KEY `idx_assunto_id`(`id`) USING BTREE, 
KEY `idx_assunto_name`(`name`(30)), 
CONSTRAINT `fk_assunto` FOREIGN KEY(`id`) REFERENCES `esc_questions`(`assunto_id`) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = INNODB AUTO_INCREMENT = 3618 DEFAULT CHARSET = utf8 COLLATE = utf8_unicode_ci 


私は私のウェブサイト上で改ページを持っています。最新のページを取得しようとすると、データ要求にかかる時間が長くなります。ここ は、このタスクのための私のSELECTです:

SELECT 
    f.*, 
    d.name disciplinas, 
    o.name orgao, 
    c.name cargo, 
    b.name banca, 
    a.name assunto 
FROM 
    `esc_questions` f 
INNER JOIN 
    `esc_bancas` b 
ON 
    f.banca_id = b.id 
INNER JOIN 
    `esc_disciplinas` d 
ON 
    f.disciplinas_id = d.id 
INNER JOIN 
    `esc_assunto` a 
ON 
    f.assunto_id = a.id 
INNER JOIN 
    `esc_orgao` o 
ON 
    f.orgao_id = o.id 
INNER JOIN 
    `esc_cargo` c 
ON 
    f.cargo_id = c.id 
LIMIT 400020, 20 

このクエリはSending Dataステージに長い時間がかかるクエリプロファイラで示しました。

Sending Data 17.6 s 99.99% 1 17.6 sがEXPLAIN
は、以下を示しています。
1 SIMPLE Dすべてのプライマリを、247

1 SIMPLE F REF idx_cargo_id、idx_orgao_id、idx_banca_id、idx_assunto_id、idx_disciplinas_id idx_disciplinas_id 4 concursos.d.id 1116

をidx_disciplinas_idでeq_ref PRIMARY Cでeq_ref PRIMARY、idx_orgao_id PRIMARY 4 concursos.f.orgao_id 1

1 SIMPLE、idx_cargo_id PRIMARY 4 concursos.f.cargo_id 1

O 1つのSIMPLE私はこの仕事が速く作るために、すべての一日を過ごしたが、1 SIMPLEでeq_ref PRIMARY、idx_bancas_id PRIMARY 4 concursos.f.banca_id 1


Bでeq_ref PRIMARY、idx_assunto_id PRIMARY 4 concursos.f.assunto_id 1

1 SIMPLE失敗。

私の選択したクエリに何が間違っているのか、またはMySQLがインデックスを使用しない理由を教えてもらえますか?

助けてください。

答えて

0

自分で解決策を見つけました。私はLIMIToffsetをJOINクエリで避ける必要があります。 これを行うには、私は準備をする必要があります:
1.私のメインテーブルから必要なジョイントなしでidsを取得します。このクエリには0が必要でした。0856秒

SELECT id FROM `esc_questions` WHERE 1 LIMIT 489980, 20 

2.あなたは、あなたのクエリを行いますために複合インデックスを作成します。私の場合、次のインデックスを使用します:

... 
KEY `idx_filter_search` (`id`,`disciplinas_id`,`assunto_id`,`orgao_id`,`cargo_id`,`banca_id`) USING BTREE, 
... 

3.最後にクエリを実行します。 Query took 0.0040 seconds

SELECT SQL_NO_CACHE 
     f.*, 
     d.name disciplinas, 
     o.name orgao, 
     c.name cargo, 
     b.name banca, 
     a.name assunto 
    FROM 
     `esc_questions` f FORCE INDEX(idx_filter_search), 
     `esc_disciplinas` d, 
     `esc_assunto` a, 
     `esc_orgao` o, 
     `esc_cargo` c, 
     `esc_bancas` b 
    WHERE 
     f.id IN(
      497442, 
      497444, 
      497445, 
      497447, 
      497449, 
      497450, 
      497452, 
      497453, 
      497454, 
      497456, 
      497458, 
      497459, 
      497461, 
      497462, 
      497464, 
      497465, 
      497467, 
      497468, 
      497470, 
      497471 
     ) AND f.disciplinas_id = d.id AND f.assunto_id = a.id AND f.orgao_id = o.id AND f.cargo_id = c.id AND f.banca_id = b.id 
    ORDER BY 
     id 

EXPLAINこのクエリは、それは私の新しく作成されたインデックスを使っていることを私に教えてくれます。
1 | SIMPLE | f | range | idx_filter_search | idx_filter_search | 4 | NULL | 20 | Using where

これは誰かを助けることを望みます。 私は正しい方向に向いてくれてありがとう@GordonLinoff。

0

あなたは間違ったアプローチをいくつか述べています。まず、クエリにはorder by句がありません。クエリは複数の実行で同じ順序で結果を返すことは保証されていません(ただし、実際のクエリではこのような問題のデバッグは本当に難しい可能性があります)。

したがって、を追加する必要があります。おそらく、esc_questionsのプライマリキーと必要なセカンダリキーが必要です。

第2に、オフセット400020はかなり大きいです。 MySQLは、400,021行を見つける前に400,020行を生成して破棄します。

私の提案は、ソートに使用される「ID」を検索し、where句を含めることです。

where ?? > $last_id 
. . . 
order by ?? 
limit 20 

これはないかもしれない(またはも)負荷を最初にスピードアップするが、それはスピードなければなりませんその後の負荷。

+0

1. PRIMARYキーでもORDER BYを使用すると、余分なものが追加されます。 EXPLAINでfilesortを使用していて、このクエリをスピードアップしません。最初はORDER BYとなっていました。 2. IDが連続していないため、%より大きいWHERE idは使用できません。しかし、私はテストし、実際にロード時間をスピードアップします。 – ganchclub

関連する問題