【问题标题】:Performance-issues with mysql + phpmysql + php 的性能问题
【发布时间】:2016-09-05 10:14:58
【问题描述】:

我有以下 PHP 脚本,它执行 MySQL 查询。

$sSql = "SELECT DISTINCT t1.* "
      . "FROM import_data t1 "
      . "INNER JOIN import_profiles imp on t1.profile_id = imp.id "
      . "WHERE imp.creditornr = " . $vendor . " "
      . "AND t1.vendor = '" . $k . "' "
      . "AND t1.importRun = (SELECT MAX(importRun) AS importRun
         FROM import_data
         WHERE sku=t1.sku
           AND profile_id = t1.profile_id)";

在原生 SQL 中,查询如下所示:

SELECT DISTINCT t1.*
FROM import_data t1
INNER JOIN import_profiles imp on t1.profile_id = imp.id
WHERE imp.creditornr = 73329
AND t1.vendor = 'rackmountit'
AND t1.importRun = (SELECT MAX(importRun) AS importRun
            FROM import_data
            WHERE sku=t1.sku
              AND profile_id = t1.profile_id)

这是其中一个查询的解释:(我运行了 > 10 个)并且数据库当前有大约 100.000 个条目(上升)。

此外,这些是在此语句中使用的表:

import_data

import_profiles

我不知道怎么做,因为我在 mysql 中不是那么好,但是有什么想法可以提高这些(子)查询的性能吗?目前他们正在运行 > 1:00,我需要对其进行优化。

谢谢,如果您需要更多信息,请告诉我。

编辑 1 添加了 CREATE TABLE 语句

SET NAMES utf8;
SET time_zone = '+00:00';

CREATE TABLE `import_data` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `profile_id` int(11) NOT NULL,
  `sku` varchar(255) NOT NULL,
  `vendor` varchar(255) NOT NULL,
  `evp` double NOT NULL,
  `ek` double NOT NULL,
  `articletext1` text NOT NULL,
  `articletext2` text NOT NULL,
  `ean` text NOT NULL,
  `stock` int(11) NOT NULL,
  `zolltarif` int(11) NOT NULL,
  `tstamp` date NOT NULL,
  `importRun` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


CREATE TABLE `import_profiles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `creditornr` int(6) NOT NULL,
  `structure` text NOT NULL,
  `updatetime` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='Import-Profile für Vorlieferanten';

【问题讨论】:

  • 你的表架构是什么,还是我错过了?在大多数情况下,进入临时状态是非常糟糕的,因为 MySQL 正在将一个临时文件写入磁盘,然后对其进行扫描。
  • 如果您的数据很有价值(很可能是这样),请将有问题的表复制到开发机器并尝试在 where 条件下为列添加索引。如果其基数小于 50%,则该供应商字段可能是理想的(如果低于 20%,则超级理想)。
  • @DasSaffe 考虑到看似少量的数据,但当您处理大量数据的那一天到来时,这可能不是问题。这部分 MySQL 手册是你的朋友 - dev.mysql.com/doc/refman/5.0/en/optimizing-innodb.html
  • @DasSaffe 找到一篇不错的博客文章,讨论索引和 InnoDB(您正在使用的表引擎)-webmonkeyuk.wordpress.com/2010/09/27/… 我必须运行,但我的离别建议。不要将索引放在高基数列上......并尽可能少地使用它们。 MySQL 将尝试将索引加载在内存中,因此减少索引至关重要。太多会影响整体性能(快速加载/卸载)。
  • @CayceK - 准备好的陈述不足以引起注意。性能问题是缺少索引。

标签: php mysql performance


【解决方案1】:

您应该为字段添加索引:import_data.profile_id、import_data.sku 和 import_profiles.creditornr 它应该会提高您的 SQL 查询速度

【讨论】:

  • 那么,当我可以选择什么类型的索引时,我选择“索引”而不是“唯一”,除非我能保证这个字段是唯一的?
  • @DasSaffe - stackoverflow.com/questions/388982/… 既然您知道要查找哪些关键字,stackoverflow 就是您最好的答案。
  • @DasSaffe 你应该添加主键。这使它们更加独特。最好(最经常)在 id 上完成。
  • @CayceK 有一段时间了,但我不相信 InnoDB 允许没有主键的表,理想情况下是一个不是自然键的表。
  • @David 现在我已经脱离了我的元素。没有注意到 InnoDB 引擎。这是一件很可靠的事情。如果您没有隐式定义主键,则不确定它是否强制使用主键/有一个。我要退出谈话了:D
【解决方案2】:

这将取决于您的架构以及数据的实际外观。

vendor 字段似乎很适合在其上放置索引。但这取决于它的独特性。如果供应商列的每一行都是唯一的,则查找其他要过滤的内容。

使用购买杂货的类比: 正如我在专栏中提到的,去临时就像有一个很长的购物清单,将整个清单的全部或几乎全部复制到一张新的纸上,然后通过副本查找清单中的哪些项目是合适的去你所在的杂货岛。

编辑:关于如何添加索引的答案,推荐阅读 cmets。 - https://stackoverflow.com/a/3002635/9908

【讨论】:

    【解决方案3】:
    import_data:  INDEX(sku, profile_id, importRun) -- for the MAX subquery
    import_data:  INDEX(vendor)
    import_profiles:  INDEX(creditornr, id)
    

    (目前还不清楚最后两个中的哪一个,但同时包含两者并没有什么坏处。)

    由于您的查询有点“分组最大值”,请参阅groupwise max

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多