繁体   English   中英

MySQL-极慢的SQL查询

[英]MySQL - Extremely slow SQL Query

我使用围攻来测试新站点的速度,发现使用AWS RDS小型实例-小型数据库,它每秒只能处理大约30个并发连接。 (我尝试使用更大的数据库并获得了更多的连接,但仍然很低)。

我已经进行了很多测试以找到弱链接,并且(例如:使用std HTML页面测试了nginx / php-fpm,包括php和memcached会话),并且一切正常……它的数据库是问题。

我在下面有2个查询-第一个只是一个测试,它可以正常/快速地运行-如果在20秒内运行100个并发连接,我可以获得3500次点击:

  $database_users = new database('dbname');
  $sql='SELECT COUNT(userid) as yes FROM login;';
  $pds=$database_users->pdo->prepare($sql); $pds->execute(array()); $row=$pds->fetch();
  echo $row['yes'];

但是,下面的查询很慢,我只有70次点击-我使用的查询是:

      $database_users = new database('dbname');
      $sql='SELECT a.countryCode FROM geoCountry AS a LEFT JOIN geoIPv4 AS b ON a.pid=b.geoCountry_pid WHERE \'2091528364\' BETWEEN startipNum AND endipNum;';
      $pds=$database_users->pdo->prepare($sql); $pds->execute(array()); $row=$pds->fetch();
      echo $row['countryCode'];

当我使用远程查询工具时,第一次查询在0.1秒内运行,第二次在0.3秒内运行。

我试图理解为什么第二个我会得到如此糟糕的表现。 php / database不会只等待查询完成然后响应。 仅0.2秒。

如果需要,我可以发送其他详细信息,例如php-fpm config。

任何建议将不胜感激-谢谢


CREATE TABLE `geoCountry` (
  `pid` tinyint(3) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
  `countryCode` char(2) NOT NULL COMMENT 'Country Code',
  `zipEnabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '1=Has Zip Codes, 0=No Zip Codes',
  `english` varchar(75) NOT NULL COMMENT 'Language',
  `indonesian` varchar(75) NOT NULL COMMENT 'Language',
  `japanese` varchar(75) NOT NULL COMMENT 'Language',
  PRIMARY KEY (`pid`),
  UNIQUE KEY `countryCode` (`countryCode`),
  KEY `zipEnabled` (`zipEnabled`),
  CONSTRAINT `geoCountry_zipEnabled` FOREIGN KEY (`zipEnabled`) REFERENCES `xfk_generic_binary` (`binary`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=249 DEFAULT CHARSET=utf8 COMMENT='Country Codes linked to Country Names'


CREATE TABLE `geoIPv4` (
  `pid` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Primary Key',
  `geoCountry_pid` tinyint(3) unsigned NOT NULL COMMENT 'geoCountry Pid',
  `startipNum` int(10) unsigned NOT NULL COMMENT 'Start IP Address',
  `endipNum` int(10) unsigned NOT NULL COMMENT 'End IP Address',
  PRIMARY KEY (`pid`),
  KEY `geoCountry_pid` (`geoCountry_pid`),
  CONSTRAINT `geoIPv4_geoCountry_pid` FOREIGN KEY (`geoCountry_pid`) REFERENCES `geoCountry` (`pid`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=148890 DEFAULT CHARSET=utf8 COMMENT='IPv4 Ranges linked to Country Codes';

*它的php-fpm是否可能不等待回复返回或与攻城如何工作有关? 注意:如果并发连接数较少,则seige似乎可以正常工作。

也许是我,但是在这种情况下使用LEFT JOIN对我来说毫无意义。

恕我直言,您的查询应该看起来像这样

SELECT a.countryCode 
  FROM geoCountry a JOIN geoIPv4 b 
    ON a.pid = b.geoCountry_pid 
 WHERE 2091528364 BETWEEN startipNum AND endipNum

确保在(startipNum, endipNum)上有覆盖索引

CREATE INDEX idx_startipNum_endipNum ON geoIPv4 (startipNum, endipNum);

与查询,即使在(startipNum,endipNum)索引的基本问题是B树索引不是查找值的最佳结构BETWEEN的两列中,由于用`startipNum`每一行<=值你“正在搜索是一个候选匹配项,而且索引了endipNum`的事实并没有任何帮助,因为必须比较每个有效`startipNum`的每个`endipNum`,即使(至少与MaxMind数据库相比,大概就是您正在使用的东西)只有一个匹配的行。

您可以通过在末尾添加LIMIT 1来大幅优化查询,因为您知道将只有一个匹配的行。 找到匹配的行后,服务器将立即停止查找。 我还发现,添加相反的索引(endipNum,startipNum)也将使优化器选择对任何给定查询而言,似乎最有效的两个索引。

我之前讨论过的(可能)更好的方法(尽管它显然令人震惊,因为它有些“开箱即用”),它是使用MySQL中的空间扩展来构建R-Tree索引。

也可以看看:

http://blog.jcole.us/2007/11/24/on-efficiently-geo-referencing-ips-with-maxmind-geoip-and-mysql-gis/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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