【问题标题】:MySQL query much slower when using join使用连接时 MySQL 查询要慢得多
【发布时间】:2017-07-07 19:00:28
【问题描述】:

我有一个 MySQL 数据库和一个查询,我正在尽我所能优化。

我不熟悉索引,所以我不知道我应该创建哪些索引。目前我没有任何索引,而且我的查询太慢了,我想。事实上,使用join 让这一切变得更慢了。我相信它会使这更快,但不是。我不明白为什么现在速度变慢了。

对索引有什么建议吗?还有什么我可以做的更好以使我的查询更快吗?

            SELECT ka_ki.kierrosnumero AS kierrosnumero
            , ka_ki.kierroskoodi AS kierroskoodi
            , ka_ki_ot.ottelunumero AS ottelunumero
            , ka_ki.haviajien_sijat_tekstina AS haviajien_sijat_tekstina
            , ka_ki.voittajien_puolelta_cupiin AS voittajien_puolelta_cupiin
            , ka_ki.haviajien_puolelta_cupiin AS haviajien_puolelta_cupiin
            , ka_ki_ot.paikka_a_ja_b_kaaviokoodi AS paikka_a_ja_b_kaaviokoodi 
            , ka_ki_ot.paikka_a_kaaviokoodi AS paikka_a_kaaviokoodi
            , ka_ki_ot.paikka_b_kaaviokoodi AS paikka_b_kaaviokoodi
            , ki_ka_ot.id AS ki_ka_ot_id
            , ki_ka_ot.kaaviopaikka_id
            , ki_ka_ot.peli_monesko_peli_ottelussa
            , ki_ka_ot.peli_pelipaikka_id
            , ki_ka_ot.peli_pelimuoto_id
            , ki_ka_ot.peli_voittopisteet
            , ki_ka_ot.peli_ajankohta_aikataulutus
            , ki_ka_ot.peli_ajankohta_alkamisaika
            , ki_ka_ot.peli_ajankohta_loppumisaika
            , ki_ka_ot.peli_paikka_a_tiimiilmo_id
            , ki_ka_ot.peli_paikka_b_tiimiilmo_id
            , ki_ka_ot.peli_paikka_a_peluri1ilm_id
            , ki_ka_ot.peli_paikka_a_peluri2ilm_id
            , ki_ka_ot.peli_paikka_b_peluri1ilm_id
            , ki_ka_ot.peli_paikka_b_peluri2ilm_id
            , ki_il.pari_joukkue_nimi_txt AS peli_paikka_b_pari_joukkue_nimi_txt
            , ki_il.sijoitusnumero_syotetty AS peli_paikka_b_sijoitusnumero_syotetty
            , ki_il.sijoitusnumero_arvottu AS peli_paikka_b_sijoitusnumero_arvottu
            , ka_il.pelaaja_oma_nimi_txt AS peli_paikka_b_peluri1_oma_nimi_txt
            FROM ki_ka_ot
                    JOIN ki_il ON ki_ka_ot.peli_paikka_b_tiimiilmo_id = ki_il.id
                    JOIN ka_il ON ki_ka_ot.peli_paikka_b_peluri1ilm_id = ka_il.id
                    JOIN ki_ka ON ki_ka.id = ki_ka_ot.kaavio_id
                    JOIN ka_ki_ot ON 
                            ki_ka.kaaviopohja_id = ka_ki_ot.kaaviopohja_id
                            AND ka_ki_ot.id = ki_ka_ot.kaaviopaikka_id
                    JOIN kaa ON ka_ki_ot.kaaviopohja_id = kaa.id
                    JOIN ka_ki ON ka_ki_ot.kierros_id = ka_ki.id
            WHERE ki_ka_ot.kaavio_id = 107
            ORDER BY ka_ki_ot.ottelunumero ASC

更新

我可以使用FROM ki_ka_ot, ki_il, ka_il, ki_ka, ka_ki_ot, kaa, ka_ki 并将几个AND 条件添加到WHERE 部分,而不是使用join。查询的结果将 100% 相同,但它会更快。我应该这样做吗?

            SELECT ka_ki.kierrosnumero AS kierrosnumero
            , ka_ki.kierroskoodi AS kierroskoodi
            , ka_ki_ot.ottelunumero AS ottelunumero
            , ka_ki.haviajien_sijat_tekstina AS haviajien_sijat_tekstina
            , ka_ki.voittajien_puolelta_cupiin AS voittajien_puolelta_cupiin
            , ka_ki.haviajien_puolelta_cupiin AS haviajien_puolelta_cupiin
            , ka_ki_ot.paikka_a_ja_b_kaaviokoodi AS paikka_a_ja_b_kaaviokoodi 
            , ka_ki_ot.paikka_a_kaaviokoodi AS paikka_a_kaaviokoodi
            , ka_ki_ot.paikka_b_kaaviokoodi AS paikka_b_kaaviokoodi
            , ki_ka_ot.id AS ki_ka_ot_id
            , ki_ka_ot.kaaviopaikka_id
            , ki_ka_ot.peli_monesko_peli_ottelussa
            , ki_ka_ot.peli_pelipaikka_id
            , ki_ka_ot.peli_pelimuoto_id
            , ki_ka_ot.peli_voittopisteet
            , ki_ka_ot.peli_ajankohta_aikataulutus
            , ki_ka_ot.peli_ajankohta_alkamisaika
            , ki_ka_ot.peli_ajankohta_loppumisaika
            , ki_ka_ot.peli_paikka_a_tiimiilmo_id
            , ki_ka_ot.peli_paikka_b_tiimiilmo_id
            , ki_ka_ot.peli_paikka_a_peluri1ilm_id
            , ki_ka_ot.peli_paikka_a_peluri2ilm_id
            , ki_ka_ot.peli_paikka_b_peluri1ilm_id
            , ki_ka_ot.peli_paikka_b_peluri2ilm_id
            , ki_il.pari_joukkue_nimi_txt AS peli_paikka_b_pari_joukkue_nimi_txt
            , ki_il.sijoitusnumero_syotetty AS peli_paikka_b_sijoitusnumero_syotetty
            , ki_il.sijoitusnumero_arvottu AS peli_paikka_b_sijoitusnumero_arvottu
            , ka_il.pelaaja_oma_nimi_txt AS peli_paikka_b_peluri1_oma_nimi_txt
            FROM ki_ka_ot
            , ki_il
            , ka_il
            , kaa
            , ka_ki
            , ka_ki_ot
            , ki_ka
            WHERE ki_ka_ot.kaavio_id = 107
            AND ki_ka_ot.peli_paikka_b_tiimiilmo_id = ki_il.id
            AND ki_ka_ot.peli_paikka_b_peluri1ilm_id = ka_il.id
            AND ki_ka.id = ki_ka_ot.kaavio_id
            AND ki_ka.kaaviopohja_id = ka_ki_ot.kaaviopohja_id
            AND ka_ki_ot.kaaviopohja_id = kaa.id 
            AND ka_ki_ot.kierros_id = ka_ki.id
            AND ka_ki_ot.id = ki_ka_ot.kaaviopaikka_id
            ORDER BY ka_ki_ot.ottelunumero ASC

更新 2

现在我修改了使用join 的原始查询。我认为它工作得更好更快,但也许有一些问题需要解决。

            SELECT ka_ki.kierrosnumero AS kierrosnumero
            , ka_ki.kierroskoodi AS kierroskoodi
            , ka_ki_ot.ottelunumero AS ottelunumero
            , ka_ki.haviajien_sijat_tekstina AS haviajien_sijat_tekstina
            , ka_ki.voittajien_puolelta_cupiin AS voittajien_puolelta_cupiin
            , ka_ki.haviajien_puolelta_cupiin AS haviajien_puolelta_cupiin
            , ka_ki_ot.paikka_a_ja_b_kaaviokoodi AS paikka_a_ja_b_kaaviokoodi 
            , ka_ki_ot.paikka_a_kaaviokoodi AS paikka_a_kaaviokoodi
            , ka_ki_ot.paikka_b_kaaviokoodi AS paikka_b_kaaviokoodi
            , ki_ka_ot.id AS ki_ka_ot_id
            , ki_ka_ot.kaaviopaikka_id
            , ki_ka_ot.peli_monesko_peli_ottelussa
            , ki_ka_ot.peli_pelipaikka_id
            , ki_ka_ot.peli_pelimuoto_id
            , ki_ka_ot.peli_voittopisteet
            , ki_ka_ot.peli_ajankohta_aikataulutus
            , ki_ka_ot.peli_ajankohta_alkamisaika
            , ki_ka_ot.peli_ajankohta_loppumisaika
            , ki_ka_ot.peli_paikka_a_tiimiilmo_id
            , ki_ka_ot.peli_paikka_b_tiimiilmo_id
            , ki_ka_ot.peli_paikka_a_peluri1ilm_id
            , ki_ka_ot.peli_paikka_a_peluri2ilm_id
            , ki_ka_ot.peli_paikka_b_peluri1ilm_id
            , ki_ka_ot.peli_paikka_b_peluri2ilm_id
            , ki_il.pari_joukkue_nimi_txt AS peli_paikka_b_pari_joukkue_nimi_txt
            , ki_il.sijoitusnumero_syotetty AS peli_paikka_b_sijoitusnumero_syotetty
            , ki_il.sijoitusnumero_arvottu AS peli_paikka_b_sijoitusnumero_arvottu
            , ka_il.pelaaja_oma_nimi_txt AS peli_paikka_b_peluri1_oma_nimi_txt
            FROM ki_ka_ot
                    JOIN ki_il ON ki_ka_ot.peli_paikka_b_tiimiilmo_id = ki_il.id
                    JOIN ka_il ON ki_ka_ot.peli_paikka_b_peluri1ilm_id = ka_il.id
                    JOIN ki_ka ON ki_ka.id = ki_ka_ot.kaavio_id
                    JOIN ka_ki_ot ON 
                            ki_ka.kaaviopohja_id = ka_ki_ot.kaaviopohja_id
/* AND ka_ki_ot.id = ki_ka_ot.kaaviopaikka_id */
                    JOIN kaa ON ka_ki_ot.kaaviopohja_id = kaa.id
                    JOIN ka_ki ON ka_ki_ot.kierros_id = ka_ki.id
            WHERE ki_ka_ot.kaavio_id = 107
AND ka_ki_ot.id = ki_ka_ot.kaaviopaikka_id /* this was moved here */
            ORDER BY ka_ki_ot.ottelunumero ASC

【问题讨论】:

  • 您没有索引:添加索引通常会有所帮助
  • @NorbertvanNobelen 是的,我明白了。我的查询范围很广,以至于我不知道应该创建哪些索引。
  • 索引应该在你加入的值上创建。其他的(大部分时间)无关紧要。
  • 是的,这应该会有所帮助:不能保证它会很好,但是任何连接性能都需要索引
  • 如果你想要这个结果,我会运行所有连接的查询。如果它真的很慢,我会分析并查看是否可以通过拆分查询来优化它,也许将其保存到一些方便的可重用表中,并与这些表一起工作以获得最终结果。

标签: mysql sql database


【解决方案1】:

JOIN 是一项高成本操作,尽管优化器试图高效执行,但如果没有您的数据的某些上下文,它就无法执行。我无法建议您应该创建特定索引,因为我也没有您的数据上下文,但您应该尝试以影响您希望执行的任何操作的方式建立索引。因此,如果您有一个连接 A 列的 JOIN,您可能希望在 A 上建立索引,以便优化器可以有效地执行该 JOIN。

【讨论】:

  • 你建议我把连接带走还是使用它们?
  • 如果需要使用join,就使用,如果不需要,就拿走。我假设您需要连接才能获取所需的数据,如果不需要,那么您需要解释为什么要使用它们。
  • 我可以使用FROM ki_ka_ot, ki_il, ka_il, ki_ka, ka_ki_ot, kaa, ka_ki 并将几个AND 条件添加到WHERE 部分。查询的结果将 100% 相同,但它会更快。我应该这样做吗?
  • 逗号表示法和JOIN 表示法应该在所有方面都等效,除了视觉上(即优化器解释相同)。因此,如果您遇到性能变化,我想您没有正确地在符号之间进行转换。
  • 我会想象“JOIN ka_ki_ot ON ki_ka.kaaviopohja_id = ka_ki_ot.kaaviopohja_id AND ka_ki_ot.id = ki_ka_ot.kaaviopaikka_id”被读取为优化器的两个连接,因为它涉及三个表而不仅仅是二。如果是这种情况,则两个查询不相等。您可以使用 EXPLAIN 和 ANALYZE 检查语句的等效性,这将使您更好地了解优化器实际看到的内容。
猜你喜欢
  • 2011-09-20
  • 1970-01-01
  • 1970-01-01
  • 2019-01-30
  • 2019-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多