【问题标题】:MySQL MyISAM sorting query makes it slowerMySQL MyISAM 排序查询使其变慢
【发布时间】:2014-05-27 01:06:32
【问题描述】:

我在 Windows Server 2008(4GB RAM)上使用 MySQL 5.1,并具有以下配置:

我有 2 个 MyISAM 表。一个在 1 个数据库 (DB1) 中,有 14 列,主要是 varchar。该表大约有 5,000,000 行,是下面的 DB1.games 表。它在 GameNumber (int(10)) 上有一个主键。

另一个表是 DB2.gameposition,由 GameNumber 列组成(链接到 DB1.games) 和 PositionCode (int(10))。该表大约有 400,000,000 行,PositionCode 上有一个索引 IX_PositionCode。

这两个数据库在同一台服务器上。

我想在 DB2.gameposition 上运行查询以查找特定的 PositionCode,并通过链接 DB1.games.Yr 字段(smallint(6) - 这代表一年)对结果进行排序。我最近才介绍的这种排序结果。 DB1.games 中这个 Yr 字段有一个索引。

在我的存储过程中,我执行以下操作:

CREATE TEMPORARY TABLE tblGameNumbers(GameNumber INT UNSIGNED NOT NULL PRIMARY KEY);

INSERT INTO tblGameNumbers(GameNumber) 
SELECT DISTINCT gp.GameNumber 
FROM DB2.gameposition gp 
WHERE PositionCode = var_PositionCode LIMIT 1000;

我只是得到 1000 来让它更快

然后将其加入 DB1.games 表。

为了从中生成一个 EXPLAIN,我取出了临时表(我在存储过程中使用)并对其进行了重构,如下面的内部子查询所示:

EXPLAIN 
SELECT * 
FROM DB1.games g 
INNER JOIN (SELECT DISTINCT gp.GameNumber 
            FROM DB2.gameposition gp 
            WHERE PositionCode = 669312116 LIMIT 1000
   ) B ON g.GameNumber = B.GameNumber 
ORDER BY g.Yr DESC 
LIMIT 0,28

运行上面的解释,我看到以下内容:

1, 'PRIMARY', '', 'ALL', '', '', '', '', 1000, '使用临时;使用文件排序' 1, 'PRIMARY', 'g', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'B.GameNumber', 1, '' 2, 'DERIVED', 'gp', 'ref', 'IX_PositionCode', 'IX_PositionCode', '4', '', 1889846, '使用临时'

在我引入 ORDER BY 子句之前,查询几乎是即时的。现在,有时它很快(取决于不同的 PositionCode),但有时它可能需要 10 秒才能返回行。在我介绍排序之前,它几乎总是即时的。不幸的是,我不太擅长解释 EXPLAIN 输出。或者如何使查询更快。

任何帮助将不胜感激!

提前致谢, 蒂姆

【问题讨论】:

    标签: mysql performance sorting sql-order-by myisam


    【解决方案1】:

    没有order by,您的limit 表示返回前28 个结果,然后查询停止。使用order by,需要检索所有结果,以便对其进行排序并返回前 28 个。

    解释说明了 MySql 在做什么:

    sort 5000000 games records by yr
    for each games record from sorted list
        get the games record by primary key (to get all the columns)
        read gamepositions by position code
            if it does not match gamenumber, discard it
            when 1000 matches found, stop reading
        end read
    end for
    

    试试这个:

    select distinct ... from gameposition gp
    inner join games g on g.gamenumber = gp.gamenumber
    where gp.positioncode = ...
    order by g.yr limit ...
    

    【讨论】:

    • 嗨,谢谢您的回复...我只对 1000 行进行排序(因为我将它们限制为 1000)所以我不明白为什么这需要很长时间...我需要在我限制它们之前获取这 1000 行,否则 ORDER BY 将没有意义......
    • 不幸的是 MySQl 没有使用我们可以看到的最有效的算法。查看更新的答案。
    • SELECT * FROM (SELECT DISTINCT GameNumber FROM DB2.gameposition) gp inner join games g on g.gamenumber = gp.gamenumber WHERE PositionCode = 669312116 order by g.yr DESC limit 0,28 但这需要真的只要在连接之后应用“Where”子句......从而有效地连接两个非常大的表......
    • 如果我将以下 (SELECT DISTINCT gp.GameNumber FROM DB2.gameposition gp WHERE PositionCode = 669312116 LIMIT 1000) 我加入到物理表 (tmp) 中并运行:EXPLAIN SELECT * FROM DB1.games g INNER JOIN tmp B ON g.GameNumber = B.GameNumber ORDER BY g.Yr DESC LIMIT 0,28 执行计划变得更好(没有派生、文件排序或临时)。在 sp 我正在创建一个临时表,在那里插入 1000 个匹配的 GameNumber,然后按上述方式加入。执行计划是否会受到您加入物理表还是临时表的影响?谢谢!
    • 我忘了提到存储过程中的物理表 tmp(我用于测试)和临时表都有以下字段:GameNumber UNSIGNED INT NOT NULL PRIMARY KEY。因此,也许主键使连接比为 EXPLAIN 修改的查询(带有子查询的查询)更快。如果是这样的话,我仍然不明白为什么有时它很慢......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-15
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 2013-09-22
    相关资源
    最近更新 更多