执行此查询需要0.0002秒:
SELECT country,city
FROM location
WHERE locID = 30296
LIMIT 1
locID 显然是一个 INDEX。
此另一个查询使用 routine ,并需要0.0005秒执行(返回30296):
SELECT IPTOLOCID(
'190.131.60.58'
)
那么,为什么这个组合查询需要1.7912秒来执行?看起来比应有的要多:
SELECT country, city
FROM location
WHERE locID = IPTOLOCID('190.131.60.58')
LIMIT 1
以防万一您发现这很有用,这些是表格和例程:
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 ;
最佳答案
我不知道为什么之前的答案被否决了,但他/她是对的。该函数针对 location
中的每一行执行。表因为:
- 否
[NOT] DETERMINISTIC
函数定义中提供了子句,因此NOT DETERMINISTIC
假设 LIMIT
子句在该过程的最后应用,此时所有行都已被扫描,并且WHERE
已检查每个人的状况
如果优化器决定不使用索引,我也不会感到惊讶,因为所有行最终都会被扫描。您可以使用 EXPLAIN
进行检查。
如果您将函数重新定义为 DETERMINISTIC
,还添加 READS SQL DATA
以避免任何意外的条款。
顺便说一句,就其结果而言,这个函数毫无意义。这应该作为 View 来实现(这样问题就不会出现)。
关于MySQL:在这个例子中使用例程来查找匹配不是应该更快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17355266/