简体   繁体   中英

Complex query optimization improve speed

I have the following query that i would like to optimize:

SELECT 
    *, @rownum := @rownum + 1 AS rank
FROM (
        SELECT
                SUM(a.id = 1) as KILLS,
                SUM(a.id = 2) as DEATHS,
                SUM(a.id = 3) as WINS,
                tb1.totalPlaytime,
                p.playerName

        FROM
        (
                SELECT
                        player_id,
                        SUM(pg.timeEnded - pg.timeStarted) as totalPlaytime
                FROM playergame pg
                INNER JOIN player p
                        ON pg.player_id = p.id
                WHERE pg.game_id IN(1, 2, 3) 
                GROUP BY
                        p.id
                ORDER BY
                        p.playerName ASC
        ) tb1
        INNER JOIN playeraction pa
                ON pa.player_id = tb1.player_id
        INNER JOIN action a
                ON pa.action_id = a.id
        INNER JOIN player p
                ON pa.player_id = p.id      
        GROUP BY
                p.id
        ORDER BY
            KILLS DESC) tb2
 WHERE tb2.playerName LIKE "%"

Somehow i am having the feeling that this is not suited for mysql. I keep a lot of actions in different tables for a good statistical approach but this slows down everything. (perhaps big data?)

This is my model

模型

Now i tried doing the following:

Combining joins in a view

I Combined the many JOINS into a VIEW. This gave me no improvements.

Index the tables

I indexed the frequently used keys, this did speed up but i can't manage to get the entire resultset below 0.613s.

Start from the action table and use left joins

This gave me a somewhat different approach but yet the joins keep being slow (the first example is still the fastest)

indexes:

索引

Any hints, tips, additions, improvements are welcome

I removed my previous answer as it was wrong and did not help, and here I am just summarizing our conversation in the comments with additional comments from myself

There are several ways to speed up the query.

  1. Make sure you are not making any redundant queries.
  2. Do as few joins as possible.
  3. Make indexes on multiple columns if possible.
  4. Make indexes clustered if needed/possible http://dev.mysql.com/doc/refman/5.0/en/innodb-index-types.html

Regarding the query you wrote in the question:

  1. Remove ORDER BY in the inner query

  2. Remove INNER JOIN in the inner query and replace GROUP BY p.id by GROUP BY player_id

  3. Few words on where indexes make sense and where not.

    In your case it would not make sense to have index on gameid on table playergame because that probably would return loads of rows. So that is all what you can do about the most inner query.

    The joins can also be a bit optimized if you know what you expect from the tables, ie, the amount of data they may face. you may think of it as a question are you building database behind a MMO game of FPS. MMO will have millions of users per game, FPS will have only a few. Also different types of games may have different actions. That would imply that you may try to optimize the query by making the index more precise. If you are able to define in the inner join of action that gameid IN (...) then creating an index on tuple (gameid, id) might help.

    Wildcart in WHERE clause. You may try to create an index on playername but it will only work if you look with a wildcard at the end of your search string, for one in the beginning you would need a separate index, and hope that query optimizer will be smart enough to switch between them each time you make a query.

    Keep in mind that more indexes imply slowed insert and delete, so keep only as few as possible.

  4. Another thing would be redesigning the structure a bit. You may still keep the database normalized, but maybe it would be usefull to have a table with summary of some games. You may have a table with summary of games that happened before yesterday, and your query would only summarize the data for today, and then join both tables if needed. Then you could optimize it by either creating and index on timestamp or partitioning table by day. Everything depends on the load you expect.

The topic is rather deep, so everything depends on what is the story behind the data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM