从 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?

的回答