使用 JOINS 的最快 MYSQL SELECT 查询(加入自身)

Fastest possible MYSQL SELECT query with JOINS (join itself)

我在索引和查询性能方面遇到了一些问题。 我目前正在做以下事情:

SELECT 
    images.imageId, 
    path, 
    fileName, 
    alt, 
    description, 
    width, 
    height 
FROM 
    images 
LEFT JOIN imagesEn ON images.imageId=imagesEn.imageId 

WHERE 

images.adId = ?

AND images.imageStatus = 1 
AND images.isPreview = 1 
AND (images.isBanner = 0 OR images.isBanner IS NULL) 

ORDER BY RAND() LIMIT 1;';

这给了我想要的图像。但我使用的是响应式图片元素,图片有较小的版本。 我有限的 sql-知识迫使我使用另一个查询,然后像这样:

SELECT 
    images.imageId, 
    relativePathToImageFromImgFolder, 
    fileName, 
    altAttribute, 
    description, 
    width, 
    height 
FROM 
    images 
LEFT JOIN imagesEn ON images.imageId=imagesEn.imageId 

WHERE 

images.adId = ? 

AND images.imageStatus = 1 
AND images.isPreview = 0 
AND images.isSmallerVersionOf = ?

ORDER by width DESC

然后我得到了两个查询和两个数组,它们为我提供了主图像以及图像的所有较小版本以创建我的图片元素。 连接是必需的,因为我有几种语言(imagesEn、imagesDe、imagesFr 等)连接文件名、给定语言的属性。 我刚刚设置了单列索引,多列索引对我来说是新的,我今天第一次听说 :D。 我在产品页面上展示类似产品的内容,我的页面生成时间约为 0.3 秒(未兑现)。我所有的其他页面都有 0.0x 秒,这也是我对该页面的目标。 另外,我正在循环中执行此查询

$query = 'SELECT name, id, url, whatever from products where productColor = "blue";';
foreach($arr as $r)
{
    $str .= '<div>';
            $str .= $r['name'] . ' ' . $r['whatever'];
            $str .= self::createPictureElementFromId($r['id']);  //this calls the above queries to create the picture element with its main image and the child images (smaller versions for smaller screens)
    $str .= '</div>';
}

return $str;

希望描述足够准确 ;)。 提前致谢

试试这个。它加入了两倍的图像 table (一个用于普通图像,第二个用于较小的版本,如果它存在的话),以及两倍的 ImageEn table 应该有描述和其他东西的翻译.

如果您只查找一张图片,您的数据库时间也不会好很多。

select字段中table的别名应该是错误的,因为我不知道每个字段在哪里。描述应该在 imagesEn 和 imagesEn2

这只会得到一张缩小版的图片。如果你有很多较小的图像,你可以加入三倍的图像 table,但恕我直言,你现在在代码中使用两个 selects 的方式应该更干净。

SELECT 
    i.imageId, 
    i.path, 
    i.fileName, 
    i.alt, 
    i.description, 
    i.width, 
    i.height,
    i2.relativePathToImageFromImgFolder, 
    i2.fileName, 
    i2.altAttribute, 
    i2.description, 
    i2.width, 
    i2.height

FROM 
    images as i
LEFT JOIN imagesEn as iEn ON i.imageId=iEn.imageId 
LEFT JOIN images as i2 on ((i2.isSmallerVersionOf = i.imageID) AND (i2.imageStatus = 1)  AND (i2.isPreview = 0))
LEFT JOIN imagesEn2 as IEn2 ON i2.imageId = iEn2.imageId

WHERE 

i2.adId = ?

AND i.imageStatus = 1 
AND i.isPreview = 1 
AND (i.isBanner = 0 OR i.isBanner IS NULL) 

ORDER BY RAND() LIMIT 1;

i.isBanner = 0 OR i.isBanner IS NULL -- 选一个。这将使您摆脱 OR,这是一个性能杀手。

然后有INDEX(adId, imageStatus, isPreview, isBanner)(顺序不限)。这应该允许过滤 运行 更快。

请提供 SHOW CREATE TABLE,因为我不得不猜测您的某些数据类型等。

为了做到 ORDER BY RAND() LIMIT 1,绕过所有的柱子,只选择其中一个是低效的。所以,改为这样做:

SELECT i.imageId, i.path, ...
    FROM ( SELECT imageId FROM images WHERE ...
               ORDER BY RAND() LIMIT 1 ) AS x
    JOIN images i  USING(imageId)

但是你需要 INDEX(adId, imageStatus, isPreview, isBanner, imageId) 以便内部查询可以 运行 完全在索引中。

"Smaller version" -- 让标志说 "this is a small image" 并将其包含在 WHEREINDEX.

Language URL -- 在上面添加另一个 JOIN 以获得特定于语言的 URL,它应该在 another table 。 table 应该有 PRIMARY KEY(imageId, lang).