Mysql 如何避免SQL中的嵌套子查询

Mysql 如何避免SQL中的嵌套子查询,mysql,performance,subquery,inner-join,Mysql,Performance,Subquery,Inner Join,我刚刚在我的网站上添加了一个标签系统,我正试图找出运行可伸缩查询的最有效方法。下面是一个基本的mysql查询,用于返回给定用户的标记匹配: SELECT scans.scan_index, scans.scan_id, scans.archive_folder FROM tags INNER JOIN interpretationtags USING (tagid) INNER JOIN interpretations USING

我刚刚在我的网站上添加了一个标签系统,我正试图找出运行可伸缩查询的最有效方法。下面是一个基本的mysql查询,用于返回给定用户的标记匹配:

SELECT
   scans.scan_index,
   scans.scan_id,
   scans.archive_folder 
FROM
   tags 
   INNER JOIN
      interpretationtags USING (tagid) 
   INNER JOIN
      interpretations USING (interpretation_id) 
   INNER JOIN
      scans 
      ON scans.scan_id = interpretations.scan_id 
      AND scans.archive_folder = interpretations.archive_folder 
   INNER JOIN
      archives 
      ON scans.archive_folder = archives.archive_folder 
WHERE
   archives.user_id = "google-authd...." 
   AND tags.tag = "tag1"
但是,当我想查询多个
标记
以进行相同的
扫描
时,它会变得很粘。您可以看到,
标记
存在于不同的
解释中,
并且每个
扫描都有多个解释。
下面是使用子查询的两个
标记的工作查询:

SELECT
   a.scan_index,
   a.scan_id,
   a.archive_folder 
FROM
   (
      SELECT
         scans.scan_index,
         scans.scan_id,
         scans.archive_folder 
      FROM
         tags 
         INNER JOIN
            interpretationtags USING (tagid) 
         INNER JOIN
            interpretations USING (interpretation_id) 
         INNER JOIN
            scans 
            ON scans.scan_id = interpretations.scan_id 
            AND scans.archive_folder = interpretations.archive_folder 
         INNER JOIN
            archives 
            ON scans.archive_folder = archives.archive_folder 
      WHERE
         archives.user_id = "google-auth2..." 
         AND tags.tag = "tag1"
   )
   as a 
   INNER JOIN
      interpretations 
      ON a.scan_id = interpretations.scan_id 
      AND a.archive_folder = interpretations.archive_folder 
   INNER JOIN
      interpretationtags USING(interpretation_id) 
   INNER JOIN
      tags USING(tagid) 
WHERE
   tags.tag = "tag2"
因为这是在LAMP堆栈上运行的,所以我已经编写了一些PHP代码来迭代
标记
,我想将其包含在这个和样式搜索中,从而构建一个多嵌套查询。这是一对三

SELECT
   b.scan_index,
   b.scan_id,
   b.archive_folder 
FROM
   (
      SELECT
         a.scan_index,
         a.scan_id,
         a.archive_folder 
      FROM
         (
            SELECT
               scans.scan_index,
               scans.scan_id,
               scans.archive_folder 
            FROM
               tags 
               INNER JOIN
                  interpretationtags USING (tagid) 
               INNER JOIN
                  interpretations USING (interpretation_id) 
               INNER JOIN
                  scans 
                  ON scans.scan_id = interpretations.scan_id 
                  AND scans.archive_folder = interpretations.archive_folder 
               INNER JOIN
                  archives 
                  ON scans.archive_folder = archives.archive_folder 
            WHERE
               archives.user_id = "google..." 
               AND tags.tag = "tag1"
         )
         as a 
         INNER JOIN
            interpretations 
            ON a.scan_id = interpretations.scan_id 
            AND a.archive_folder = interpretations.archive_folder 
         INNER JOIN
            interpretationtags USING(interpretation_id) 
         INNER JOIN
            tags USING(tagid) 
      WHERE
         tags.tag = "tag2"
   )
   as b 
   INNER JOIN
      interpretations 
      ON b.scan_id = interpretations.scan_id 
      AND b.archive_folder = interpretations.archive_folder 
   INNER JOIN
      interpretationtags USING(interpretation_id) 
   INNER JOIN
      tags USING(tagid) 
WHERE
   tags.tag = "tag3"

即使是4个嵌套的子查询也能以最少的数据快速运行,但在处理10万行数据时,我认为这不是一个可伸缩的解决方案。我如何才能在不恢复到这种低效的丑陋代码的情况下完成这项工作?

如果没有表结构和示例数据,很难确定,但我认为这是在错误的方向上进行的。您应该从扫描开始,找到所有适当的标记,然后对这些标记进行筛选(然后在
表达式中使用一个简单的
):


请注意,根据您的
选择
字段列表,我认为您实际上根本不需要将
加入到
存档

请参阅。此外,关于查询优化的问题总是需要对给定查询进行解释。谢谢Nick。这很接近,但它会得到所有使用tag1或tag2的扫描。@UltrasondJelly那么您想要使用tag1和tag2的扫描?你的问题不是100%清楚很抱歉,这是目标。你应该能够将
按扫描分组。扫描索引,扫描id,扫描id,扫描存档文件夹(COUNT)(DISTINCT tags.tag)=2
添加到查询中以实现这一点。这在这里是可行的,但是如果使用tag1的同一扫描有两种解释呢?
SELECT
   scans.scan_index,
   scans.scan_id,
   scans.archive_folder 
FROM
   scans
   INNER JOIN
      archives 
      ON scans.archive_folder = archives.archive_folder 
   INNER JOIN
      interpretations 
      ON scans.scan_id = interpretations.scan_id 
      AND scans.archive_folder = interpretations.archive_folder 
   INNER JOIN
      interpretationtags USING (interpretation_id) 
   INNER JOIN
      tags USING (tagid) 
WHERE
   archives.user_id = "google-authd...." 
   AND tags.tag IN("tag1", "tag2")