为什么我的MySQL连接查询速度如此之慢?

时间:2014-12-19 08:38:20

标签: mysql join indexing

我正在尝试在一个包含大约30,000行的表(history_details)上运行查询,并且需要连接多个表(历史记录,房间,室友,属性,列表,学生和管理员)。

  1. 第一次加入历史记录表非常简单。
  2. 只有满足条件才能添加下3个连接(房间,室友,属性)。在这种情况下,它查看history_details表中的listing_type列的值是什么,并且如果它是适当的值,则应该将该连接添加到查询中。
  3. 接下来的3个连接有几个条件需要满足才能包含它们,但在这种情况下它可能是任何OR条件。

                    SELECT SQL_CALC_FOUND_ROWS 
                        history_details.history_id,
                        history_details.listing_type,
                        history_details.listing_id,
                        history_details.date_added,
                        history_details.field,
                        history_details.before_value,
                        history_details.after_value,
                        history_details.edit_group,
                        history_details.email,
                        history_details.name,
                        history_details.correction_message,
                        history_details.photo_filepath,
                        history.history_message,
                        listers.first_name,
                        listers.last_name,
                        students.first_name,
                        students.last_name,
                        admin.first_name,
                        admin.last_name
                    FROM history_details
                    LEFT JOIN history
                        ON history_details.history_id = history.history_id
                    LEFT JOIN rooms
                        ON history_details.listing_type="room" AND rooms.room_id = history_details.listing_id
                    LEFT JOIN roommates
                        ON history_details.listing_type="roommate"
                        AND roommates.roommate_id = history_details.listing_id
                    LEFT JOIN properties
                        ON history_details.listing_type="property"
                        AND properties.property_id = history_details.listing_id
                    LEFT JOIN listers
                        ON (history_details.listing_type="lister" AND listers.lister_id = history_details.listing_id)
                        OR (history_details.listing_type="property" AND listers.lister_id = properties.lister_id)
                        OR (history_details.listing_type="room" AND rooms.lister_type="lister" AND listers.lister_id = rooms.lister_id)
                    LEFT JOIN students
                        ON (history_details.listing_type="student" AND students.student_id = history_details.listing_id)
                        OR (history_details.listing_type="roommate" AND students.student_id = roommates.student_id)
                        OR (history_details.listing_type="room" AND rooms.lister_type="student" AND students.student_id = rooms.lister_id)
                    LEFT JOIN admin
                        ON history_details.listing_type="admin" AND admin.admin_id = history_details.listing_id
                    LIMIT 0,100
    
  4. 它给了我正确的结果,但它需要73秒才能运行。我添加了索引,但我不确定它们是否被使用。这是我使用EXPLAIN SELECT SQL_CALC_FOUND_ROWS ....

    运行Explain时显示的内容

    enter image description here

    这是我使用EXPLAIN SELECT ....运行Explain时显示的内容 enter image description here

    这些是我添加到各种表中的索引: 的 history_details enter image description here

    属性 enter image description here

    enter image description here

    室友 enter image description here

    你能告诉我我的索引是否被使用?另外,如何改进查询,表结构或索引以提高速度?

    修改 感谢Amadan的有用建议,它现在以147毫秒而不是73秒运行。这是我最终使用的最终查询:

                    SELECT SQL_CALC_FOUND_ROWS 
                        history_details.*,
                        listers.first_name AS lister_first_name,
                        listers.last_name AS lister_last_name,
                        NULL AS student_first_name,
                        NULL AS student_last_name,
                        NULL AS admin_first_name,
                        NULL AS admin_last_name
                    FROM history_details
                    LEFT JOIN history
                        ON history_details.history_id = history.history_id
                    LEFT JOIN listers
                        ON listers.lister_id = history_details.listing_id
                    WHERE history_details.listing_type="lister"
    
                    UNION
    
                    SELECT history_details.*,
                        NULL AS lister_first_name,
                        NULL AS lister_last_name,
                        students.first_name AS student_first_name,
                        students.last_name AS student_last_name,
                        NULL AS admin_first_name,
                        NULL AS admin_last_name
                    FROM history_details
                    LEFT JOIN history
                        ON history_details.history_id = history.history_id
                    LEFT JOIN students
                        ON students.student_id = history_details.listing_id
                    WHERE history_details.listing_type="student"
    
                    UNION
    
                    SELECT history_details.*,
                        listers.first_name AS lister_first_name,
                        listers.last_name AS lister_last_name,
                        NULL AS student_first_name,
                        NULL AS student_last_name,
                        NULL AS admin_first_name,
                        NULL AS admin_last_name
                    FROM history_details
                    LEFT JOIN history
                        ON history_details.history_id = history.history_id
                    LEFT JOIN properties
                        ON properties.property_id = history_details.listing_id
                    LEFT JOIN listers
                        ON listers.lister_id = properties.lister_id
                    WHERE history_details.listing_type="property"
    
                    UNION
    
                    SELECT history_details.*,
                        listers.first_name AS lister_first_name,
                        listers.last_name AS lister_last_name,
                        students.first_name AS student_first_name,
                        students.last_name AS student_last_name,
                        NULL AS admin_first_name,
                        NULL AS admin_last_name
                    FROM history_details
                    LEFT JOIN history
                        ON history_details.history_id = history.history_id
                    LEFT JOIN rooms
                        ON rooms.room_id = history_details.listing_id
                    LEFT JOIN listers
                        ON (rooms.lister_type="lister" AND listers.lister_id = rooms.lister_id)
                    LEFT JOIN students
                        ON (rooms.lister_type="student" AND students.student_id = rooms.lister_id)
                    WHERE history_details.listing_type="room"
    
                    UNION
    
                    SELECT history_details.*,
                        NULL AS lister_first_name,
                        NULL AS lister_last_name,
                        students.first_name AS student_first_name,
                        students.last_name AS student_last_name,
                        NULL AS admin_first_name,
                        NULL AS admin_last_name
                    FROM history_details
                    LEFT JOIN history
                        ON history_details.history_id = history.history_id
                    LEFT JOIN roommates
                        ON roommates.roommate_id = history_details.listing_id
                    LEFT JOIN students
                        ON students.student_id = roommates.student_id
                    WHERE history_details.listing_type="roommate"
    
                    UNION
    
                    SELECT history_details.*,
                        NULL AS lister_first_name,
                        NULL AS lister_last_name,
                        NULL AS student_first_name,
                        NULL AS student_last_name,
                        admin.first_name AS admin_first_name,
                        admin.last_name AS admin_last_name
                    FROM history_details
                    LEFT JOIN history
                        ON history_details.history_id = history.history_id
                    LEFT JOIN admin
                        ON admin.admin_id = history_details.listing_id
                    WHERE history_details.listing_type="admin"
                    ORDER BY history_details_id DESC
                    LIMIT 0,100
    

1 个答案:

答案 0 :(得分:1)

keyNULL的行,它不使用这些表的任何索引。即listersstudents未被优化。这是因为它上面的索引是不可能的,因为你使用OR来生成它。进行多次查询,每次history_details.listing_type一次,UNION次。是的,它看起来很丑陋,重复很多,但速度会很快。

联盟语法如下:

SELECT ...
WHERE history_details.listing_type="lister"
UNION
SELECT ...
WHERE history_details.listing_type="property"
UNION
SELECT ...
WHERE history_details.listing_type="room"
UNION
SELECT ...
WHERE history_details.listing_type="admin"
....
...
ORDER BY whatever
LIMIT whatever, whatever

确保每个SELECT具有相同数量的字段(因此您甚至必须执行无用的连接,但它们将很快,因为它们将被编入索引)。 ...基本上是您的整个查询(SELECT field1, field2... FROM table1 LEFT JOIN table2 ON condition ...),但从ORlister条款中取出studentUNION将组合子选择的所有行。 ORDERLIMIT将适用于结合的结果,而不是最后的SELECT