SQL查询花费太多时间(3个连接)

时间:2016-12-31 12:09:09

标签: mysql database

我遇到了SQL查询的问题。我正在开发一个php网站,为了避免提出太多疑问,我更愿意做一个大的看起来像:

        select m.*, cj.*, cjb.*, me.pseudo as pseudo_acheteur
        from mercato m
        JOIN cartes_joueur cj
        ON m.ID_carte = cj.ID_carte_joueur
        JOIN cartes_joueur_base cjb
        ON cj.ID_carte_joueur_base = cjb.ID_carte_joueur_base
        JOIN membres me
        ON me.ID_membre = cj.ID_membre
        where not exists (select * from mercato_encheres me where me.ID_mercato = m.ID_mercato)
        and cj.ID_membre = 2
        and m.status <> 'cancelled'
        ORDER BY total_carac desc, cj.level desc, cjb.nom_carte asc

这应归还会员出售的所有卡,而不会下注。在结果中,我需要所有信息来显示它们。

  

以下是每个表格中的近似行:

     
      
  • mercato:1200

  •   
  • cartes_joueur:800 000

  •   
  • carte_joueur_base:62
  •   
  • membres:2000
  •   
  • mercato_enchere:15 000
  •   

我试图通过删除旧数据来减少它们(在开发环境中);但查询仍然需要10~15秒才能执行(这在网站上太长了)

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我们来看看。

  1. *子句中使用SELECT 对查询效果 。为什么?这很浪费。它不必要地增加了服务器必须处理的数据量,并且在JOIN s的情况下,可以强制处理具有重复值的列。如果您可以这样做,请尝试枚举所需的列。

  2. 您的表可能没有有用的索引来加速这一点。我们无法分辨。请注意,MySQL无法在单个查询中利用多个索引,因此要快速查询,通常需要精心选择的复合索引。我建议你尝试在(ID_membre, ID_carte_jouer, ID_carte_joueur_base)表上定义索引cartes_joueur。为什么?您的查询在第一列上匹配相等,然后在ON条件下使用第二列和第三列。

  3. 我经常发现用最大的表(大多数行)编写查询有助于我清楚地思考优化问题。在您的情况下,您的最大表格为cartes_jouer,您只从该表中选择一个ID_membre值。您最明确的优化途径是您只需要检查该表中大约400行而不是800 000行的知识。适当的复合索引将使这成为可能,并且最容易想象索引的列如果表格在您的查询中排在第一位。

  4. 你有一个相关的子查询 - 这个。

    where not exists (select * 
                        from mercato_encheres me
                       where me.ID_mercato = m.ID_mercato)
    
  5. MySQL的查询计划程序在看到它时可能是愚蠢的字面意思,运行数千次。在你的情况下,它更糟糕:它有SELECT *:见上面的第1点。

    应该重构使用LEFT JOIN ... IS NULL模式。这是怎么回事。

      select whatever
        from mercato m
        JOIN ...
        JOIN ...
        LEFT JOIN mercato_encheres mench ON mench.ID_mercato = m.ID_mercato
       WHERE mench.ID_mercato IS NULL
         and ...
       ORDER BY ...
    

    说明:LEFT JOIN而不是普通内部JOIN的使用允许mercato表中的行保留在输出中,即使ON条件与它们中的表不匹配也是如此mercato_encheres表。不匹配的行为第二个表获取NULL值。 mench.ID_mercato IS NULL子句中的WHERE条件然后仅选择 不匹配的行。