2

This query takes 0.0002 secs to execute:

SELECT country,city
FROM location
WHERE locID = 30296
LIMIT 1

locID is obviously an INDEX.

This other query uses a routine, and takes 0.0005 secs to execute (it returns 30296):

SELECT IPTOLOCID(
'190.131.60.58'
)

Then, why does this combined query take 1.7912 secs to execute? Seems way more than it should be:

SELECT country, city
FROM location
WHERE locID = IPTOLOCID('190.131.60.58')
LIMIT 1

Just in case you find this useful, these are the tables and the routine:

CREATE TABLE  `blocks` (
  `startIPNum` int(10) unsigned NOT NULL,
  `endIPNum` int(10) unsigned NOT NULL,
  `locID` int(10) unsigned NOT NULL,
  PRIMARY KEY  (`startIPNum`,`endIPNum`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 PACK_KEYS=1 DELAY_KEY_WRITE=1;

CREATE TABLE  `location` (
  `locID` int(10) unsigned NOT NULL,
  `country` char(2) default NULL,
  `region` char(2) default NULL,
  `city` varchar(45) default NULL,
  `postalCode` char(7) default NULL,
  `latitude` double default NULL,
  `longitude` double default NULL,
  `dmaCode` char(3) default NULL,
  `areaCode` char(3) default NULL,
  PRIMARY KEY  (`locID`),
  KEY `Index_Country` (`country`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED;

DELIMITER $$

DROP FUNCTION IF EXISTS `IPTOLOCID` $$
CREATE FUNCTION `IPTOLOCID`( ip VARCHAR(15)) RETURNS int(10) unsigned
BEGIN
  DECLARE ipn INTEGER UNSIGNED;
  DECLARE locID_var INTEGER;
  IF ip LIKE '192.168.%' OR ip LIKE '10.%' THEN
    RETURN 0;
  END IF;
  SET ipn = INET_ATON(ip);
  SELECT locID INTO locID_var
    FROM `blocks`
    INNER JOIN
      (SELECT MAX(startIPNum) AS start
       FROM `blocks`
       WHERE startIPNum <= ipn) AS s
    ON (startIPNum = s.start)
    WHERE endIPNum >= ipn;
  RETURN locID_var;
END $$

DELIMITER ;
4

2 回答 2

3

我不知道为什么之前的答案被否决了,但他/她是对的。该函数针对表中的每一行执行,location因为:

  • 函数定义中没有[NOT] DETERMINISTIC提供子句,因此NOT DETERMINISTIC假定
  • LIMIT子句在过程的最后应用,此时所有行都已被扫描,并且每个行的WHERE条件都已检查

如果优化器决定不使用索引,我也不会感到惊讶,因为最终将扫描所有行。你可以用EXPLAIN

如果将函数重新定义为DETERMINISTIC,还要添加READS SQL DATA子句以避免任何意外。

顺便说一句,就其结果而言,此功能是无意义的。这应该作为一个视图来实现(这样问题就不适用了)。

于 2013-06-28T00:40:26.653 回答
0

当您运行查询时,首先发生 SELECT,然后 WHERE 进入并开始过滤 SELECT。因此,在您的查询中,每一个 SELECT 行都会运行您的 IPTOLOCID 函数,然后输出您的数据。

于 2013-06-28T00:28:42.880 回答