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

时间:2017-03-27 08:42:43

标签: php mysql performance select indices

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

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。 我在产品页面上显示类似producte的内容,而我的页面生成时间约为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;

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

2 个答案:

答案 0 :(得分:0)

试试这个。它连接两次图像表(一个用于普通图像,第二个用于较小版本,如果它存在),两个ImageEn表应该具有描述和其他东西的翻译。

如果你只是在寻找一张图片,那么你的数据库时间会好得多。

选择字段中表格的别名应该是错误的,因为我不知道每个字段的位置。描述应该在imagesEn和imagesEn2

这只会获得一个较小版本的图像。如果你有很多较小的图像,你可以连接三次图像表,但恕我直言,它应该更清晰,就像你现在在代码中做两次选择一样。

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;

答案 1 :(得分:0)

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),以便内部查询可以完全在索引中运行。

“较小的版本” - 让国旗说“这是一张小图片”并将其包含在WHEREINDEX中。

语言网址 - 向上方添加另一个JOIN以获取特定于语言的网址,该网址应位于另一个表格中。该表格应为PRIMARY KEY(imageId, lang)