从 mySQL 中获取此数据的更快方法
Quicker way to get this data out of mySQL
我目前这样做是为了从我们的 table:
获取一些数据
SELECT DISTINCT(CategoryID),Distance FROM glinks_DistancesForTowns WHERE LinkID = $linkID ORDER BY Distance LIMIT 20
我正在对我们拥有的每个 link id(50k 奇数)进行迭代。我正在用 Perl 处理它们:
my @cats;
while (my ($catid,$distance) = $sth->fetchrow) {
push @cats, $cat;
}
我正在尝试查看是否有更好的方法在使用 MySQL 的子查询中执行此操作,而不是执行 50k 个较小的查询(即每个 link 一个)
table的基本结构是:
glinks_Links
ID
glinks_DistancesForTowns
LinkID
CategoryID
Distance
我确定一定有一种简单的方法可以做到这一点 - 但我只是没有看到它。
根据要求 - 这是 table 结构的转储。它实际上比这更复杂,但其他字段只是保存值,所以我将这些位去掉以提供更清晰的结构概览:
CREATE TABLE `glinks_DistancesForTowns` (
`LinkID` int(11) DEFAULT NULL,
`CategoryID` int(11) DEFAULT NULL,
`Distance` float DEFAULT NULL,
`isPaid` int(11) DEFAULT NULL,
KEY `LinkID` (`LinkID`),
KEY `CategoryID` (`CategoryID`,`isPaid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
CREATE TABLE `glinks_Links` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Title` varchar(100) NOT NULL DEFAULT '',
`URL` varchar(255) NOT NULL DEFAULT 'http://',
PRIMARY KEY (`ID`),
KEY `booking_hotel_id_fk` (`booking_hotel_id_fk`)
) ENGINE=MyISAM AUTO_INCREMENT=617547 DEFAULT CHARSET=latin1
这就是我所希望的:
SELECT glinks_Links.ID FROM glinks_Links as links, glinks_DistancesForTowns as distance (
SELECT DISTINCT(CategoryID),Distance FROM distance WHERE distance.LinkID = links.ID ORDER BY Distance LIMIT 20
)
但显然那是行不通的;)
听起来您想要每个 link 距离排名前 20 的城镇,对吗?
MySQL 8.0 支持window 函数,查询语句可以这样写:
WITH cte AS (
SELECT l.ID, ROW_NUMBER() OVER(PARTITION BY l.ID ORDER BY d.Distance) AS rownum
FROM glinks_Links as l
JOIN glinks_DistancesForTowns AS d ON d.LinkID = l.ID
) SELECT ID FROM cte WHERE rownum <= 20;
8.0 之前的版本不支持 SQL 的这些功能,因此您必须通过用户定义的变量或自连接来发挥创意。例如,参见我对 How to SELECT the newest four items per category?
的回答
我目前这样做是为了从我们的 table:
获取一些数据SELECT DISTINCT(CategoryID),Distance FROM glinks_DistancesForTowns WHERE LinkID = $linkID ORDER BY Distance LIMIT 20
我正在对我们拥有的每个 link id(50k 奇数)进行迭代。我正在用 Perl 处理它们:
my @cats;
while (my ($catid,$distance) = $sth->fetchrow) {
push @cats, $cat;
}
我正在尝试查看是否有更好的方法在使用 MySQL 的子查询中执行此操作,而不是执行 50k 个较小的查询(即每个 link 一个)
table的基本结构是:
glinks_Links
ID
glinks_DistancesForTowns
LinkID
CategoryID
Distance
我确定一定有一种简单的方法可以做到这一点 - 但我只是没有看到它。
根据要求 - 这是 table 结构的转储。它实际上比这更复杂,但其他字段只是保存值,所以我将这些位去掉以提供更清晰的结构概览:
CREATE TABLE `glinks_DistancesForTowns` (
`LinkID` int(11) DEFAULT NULL,
`CategoryID` int(11) DEFAULT NULL,
`Distance` float DEFAULT NULL,
`isPaid` int(11) DEFAULT NULL,
KEY `LinkID` (`LinkID`),
KEY `CategoryID` (`CategoryID`,`isPaid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
CREATE TABLE `glinks_Links` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Title` varchar(100) NOT NULL DEFAULT '',
`URL` varchar(255) NOT NULL DEFAULT 'http://',
PRIMARY KEY (`ID`),
KEY `booking_hotel_id_fk` (`booking_hotel_id_fk`)
) ENGINE=MyISAM AUTO_INCREMENT=617547 DEFAULT CHARSET=latin1
这就是我所希望的:
SELECT glinks_Links.ID FROM glinks_Links as links, glinks_DistancesForTowns as distance (
SELECT DISTINCT(CategoryID),Distance FROM distance WHERE distance.LinkID = links.ID ORDER BY Distance LIMIT 20
)
但显然那是行不通的;)
听起来您想要每个 link 距离排名前 20 的城镇,对吗?
MySQL 8.0 支持window 函数,查询语句可以这样写:
WITH cte AS (
SELECT l.ID, ROW_NUMBER() OVER(PARTITION BY l.ID ORDER BY d.Distance) AS rownum
FROM glinks_Links as l
JOIN glinks_DistancesForTowns AS d ON d.LinkID = l.ID
) SELECT ID FROM cte WHERE rownum <= 20;
8.0 之前的版本不支持 SQL 的这些功能,因此您必须通过用户定义的变量或自连接来发挥创意。例如,参见我对 How to SELECT the newest four items per category?
的回答