【问题标题】:Extremely slow MySQL query极慢的 MySQL 查询
【发布时间】:2012-05-03 01:51:50
【问题描述】:

我在 MySQL 中有两个表,table1 有 1,013,347 个实体和 38 个属性,table2 有 7,343,905 个实体和 10 个属性。在下面的查询中(它应该获取分页的行数),table1.ID 是一个 PK,table2.ID 是它的 FK(两者都被索引),如果 HAVING 子句超过一定百分比,则获取该值,在这种情况下为 50%

SELECT SQL_CALC_FOUND_ROWS * 
FROM table1 INNER JOIN table2 ON table1.ID = table2.ID 
WHERE table1.attribute1 LIKE 'D%' 
GROUP BY table2.ID 
HAVING (COUNT(table2.ID) * (100/18)) >= '50'

即使在我在这里发布的简化状态下,通过命令行运行此查询也需要不少于 5 分钟。我知道我必须对查询、PHP 代码(通过 PHP 变量分配值“50”和“D”)和/或我的 MySQL 配置进行更改以加快速度(我正在使用具有默认配置的最新 XAMPP)。任何帮助将不胜感激。

EDIT1:所有属性都是 TINYTEXT,除了 ID 属性是 VARCHAR(9)。

EDIT2: EXPLAIN SELECT... 返回:

+----+-------------+--------+------+---------------+-------------+---------+------+---------+---------------------------------+
| id | select_type | table  | type | possible_keys | key         | key_len | ref  | rows    | Extra                           |
+----+-------------+--------+------+---------------+-------------+---------+------+---------+---------------------------------+
|  1 | SIMPLE      | table2 | ALL  | NULL          | NULL        | NULL    | NULL | 7343905 | Using temporary; Using filesort |
|  1 | SIMPLE      | table1 | ref  | ID            | ID          | 29      | func |       1 | Using where                     |
+----+-------------+--------+------+---------------+-------------+---------+------+---------+---------------------------------+
2 rows in set (0.00 sec)

【问题讨论】:

  • EXPLAIN SELECT ... 得到什么?
  • 它不会影响性能但不要引用数字,'50',它最终会绊倒你。加上强制性编码恐怖"Pagination is dead" reference.
  • 您是否为 table1.attribute1 编制了索引,而您正在针对它执行LIKE
  • 不,我没有,我现在就这样做,谢谢!
  • @deathonater 您也可以在此表上发布索引。慢的原因是文件排序选项。我还要补充 Ben 的观察,如果你引用数字,那么 MySQL 需要进行 atoi 转换以进行比较。我在早期版本中看到这会影响性能,但不确定您使用的是哪个版本。

标签: php mysql performance optimization


【解决方案1】:

以下是一些潜在的改进:

  • 您正在使用 VARCHAR(9) 类型的 ID,并且正在使用这些字段执行连接。引入整数代理键而不是 varchars 来加速连接可能是个好主意。见this discussion
  • LIKE 运算符通常很昂贵。考虑您的使用情况;就像 Marc 建议的那样,您应该索引 table1.attribute1。
  • 也许您可以通过完全省略 LIKE 来加快查询速度:例如,您可以使用 RIGHT() 而不是使用 'D%',尽管我不确定它是否会更快。如果表中的数据不经常更改,您可以创建一个新的索引列,其中 table1.attribute1 值的开头是预先切割的;然而,这取决于 php 脚本在 LIKE 之后插入的值。

【讨论】:

    【解决方案2】:

    提高性能的一些想法

    1. 索引 table2.ID(必须)和 table1.ID 也是
    2. 如果可能,将 id 列 bigint 和 table1.attribute1 设置为 varchar。请注意根据列的假定数据长度为 varchar 列定义适当的大小
    3. 与其在 SQL (100/18) 中进行计算,不如像这样替换它

      有 (COUNT(table2.ID) * (5.5555)) >= 50

    (由于 table2.ID 现在是 bigint,数学比较必须稍微快一些)

    正如我所见,like 子句在此查询中至关重要,尽管 like 很昂贵,但如果您也索引 table1.attribute1 会更好。

    希望对你有帮助

    【讨论】:

    • attribute1 上的索引会加快like 子句的速度吗?
    猜你喜欢
    • 1970-01-01
    • 2011-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    • 1970-01-01
    相关资源
    最近更新 更多