繁体   English   中英

MySQL LEFT JOIN或WHERE IN SUBQUERY

[英]MySQL LEFT JOIN or WHERE IN SUBQUERY

我需要一条建议,现在构建一个应用程序,我需要在相当大的表上运行一些查询,可能是非常频繁的,所以我试图获得最佳的方法性能明智。

我有以下2个表格:

专辑:

+---------------+--------------+------+-----+---------+----------------+
|     Field     |     Type     | Null | Key | Default |     Extra      |
+---------------+--------------+------+-----+---------+----------------+
| id            | int(11)      | NO   | PRI | NULL    | auto_increment |
| eventid       | int(11)      | NO   | MUL | NULL    |                |
| album         | varchar(200) | NO   |     | NULL    |                |
| filename      | varchar(200) | NO   |     | NULL    |                |
| obstacle_time | time         | NO   |     | NULL    |                |
+---------------+--------------+------+-----+---------+----------------+

和关键字:

+-------------+--------------+------+-----+---------+----------------+
|    Field    |     Type     | Null | Key | Default |     Extra      |
+-------------+--------------+------+-----+---------+----------------+
| id          | int(11)      | NO   | PRI | NULL    | auto_increment |
| eventid     | int(11)      | NO   | MUL | NULL    |                |
| filename    | varchar(200) | NO   |     | NULL    |                |
| bibnumbers  | varchar(200) | NO   |     | NULL    |                |
| gender      | varchar(20)  | YES  |     | NULL    |                |
| top_style   | varchar(20)  | YES  |     | NULL    |                |
| pants_style | varchar(20)  | YES  |     | NULL    |                |
| other       | varchar(20)  | YES  |     | NULL    |                |
| cap         | varchar(200) | NO   |     | NULL    |                |
| tshirt      | varchar(200) | NO   |     | NULL    |                |
| pants       | varchar(200) | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

两个表都声明了unique_index,它是eventid+filename列的约束。

两个表都包含有关某些图像的信息,但是相册表立即可用(只要我有图像),而关键字表通常在手动标记图像完成几天后可用

现在,一旦启用标记,我会让人们搜索所有类型的东西,但由于结果可能很大(高达10.000或更多)我只是以小块显示它们所以浏览器不会因尝试而被杀死加载大量图像,因此我的服务器将被大量的查询请求命中(每次访问者滚动到页面底部时,ajax查询将返回下一个图像块)。

现在我的问题是,以下哪个查询性能更好:

SELECT `albums`.`filename`,`basket`.`id`,`albums`.`id`,`obstacle_time`
FROM `albums`
LEFT JOIN `basket`
    ON `basket`.`eventid` = `albums`.`eventid`
        AND `basket`.`fileid` = `albums`.`id`
        AND `basket`.`visitor_id` = 1
LEFT JOIN `keywords`
    ON `keywords`.`eventid` = `albums`.`eventid`
        AND `albums`.`filename` = `keywords`.`filename`
WHERE
    `albums_2015`.`eventid` = 1
    AND `album` LIKE '%string%'
    AND `obstacle_time` >= '08:00:00'
    AND `obstacle_time` <= '14:11:10'
    AND `gender` = 1
    AND `top_style` REGEXP '[[:<:]]0[[:>:]]|[[:<:]]1[[:>:]]'
    AND `cap` = '2'
    AND `tshirt` = '1'
    AND `pants` = '3'
ORDER BY `obstacle_time`
LIMIT X, 10

或者在WHERE使用IN CLAUSE:

SELECT `albums`.`filename`,`basket`.`id`,`albums`.`id`,`obstacle_time` 
FROM `albums` 
LEFT JOIN `basket` 
    ON `basket`.`eventid` = `albums`.`eventid` 
        AND `basket`.`fileid` = `albums`.`id` 
        AND `basket`.`visitor_id` = 1 
WHERE 
    `albums_2015`.`eventid` = 1 
    AND `album` LIKE '%string%' 
    AND `obstacle_time` >= '08:00:00' 
    AND `obstacle_time` <= '14:11:10' 
    AND `filename` IN (
        SELECT `filename` 
        FROM `keywrods` 
        WHERE
            `eventid` = 1 
            AND `gender` = 1 
            AND `top_style` REGEXP '[[:<:]]0[[:>:]]|[[:<:]]1[[:>:]]' 
            AND `cap` = '2' 
            AND `tshirt` = '1' 
            AND `pants` = '3'
    )
ORDER BY `obstacle_time`
LIMIT X, 10

我曾经看过类似的问题,但无法弄清楚哪个是最好的行动方案。

到目前为止,我的理解是:

  • 使用LEFT JOIN可以利用INDEXING,但是!!! 如果我使用它,即使我只需要一个非常小的结果集,我也会获得表的完全连接,因此加入数千行只是为了过滤掉大部分行,这几乎是一个浪费。

  • 使用IN和子查询没有索引??? 我不是百分之百地确定这一点,我使用的是MySQL 5.6并且我的理解最好,因为5.6甚至子查询都会自动索引我的MySQL。 我认为当结果被显着过滤时,此方法会有好处,如果子查询将返回所有可能的文件名,则不确定是否会有任何好处。

作为脚注问题:

  • 我是否应该考虑在第一个查询时将整个结果返回给客户端,并使用客户端(HTML)技术逐步加载图像而不是每次都重新查询服务器?

  • 我是否应该考虑将2个表合并为1,这将产生多大的性能影响? (由于种种原因可能很棘手,问题中没有任何地方)

谢谢。

编辑1

解释JOIN查询:

+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+
| id | select_type |     table     |  type  | possible_keys |     key      | key_len |                  ref                   | rows |                       Extra                        |
+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+
|  1 | SIMPLE      | albums_2015   | ref    | unique_index  | unique_index | 4       | const                                  | 6475 | Using where; Using temporary; Using filesort       |
|  1 | SIMPLE      | basket        | ALL    | NULL          | NULL         | NULL    | NULL                                   |    2 | Using where; Using join buffer (Block Nested Loop) |
|  1 | SIMPLE      | keywords_2015 | eq_ref | unique_index  | unique_index | 206     | const,mybibnumber.albums_2015.filename |    1 | Using index                                        |
+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+

使用WHERE IN:

+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+--+
| id | select_type |     table     |  type  | possible_keys |     key      | key_len |                  ref                   | rows |                       Extra                        |  |
+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+--+
|  1 | SIMPLE      | albums_2015   | ref    | unique_index  | unique_index | 4       | const                                  | 6475 | Using where; Using temporary; Using filesort       |  |
|  1 | SIMPLE      | keywords_2015 | eq_ref | unique_index  | unique_index | 206     | const,mybibnumber.albums_2015.filename |    1 | Using where                                        |  |
|  1 | SIMPLE      | basket        | ALL    | NULL          | NULL         | NULL    | NULL                                   |    2 | Using where; Using join buffer (Block Nested Loop) |  |
+----+-------------+---------------+--------+---------------+--------------+---------+----------------------------------------+------+----------------------------------------------------+--+

编辑2

我无法设置SQL Fiddler(不断出错的错误),所以我在我的一台服务器上创建了一个测试数据库。

地址: http//188.165.217.185/phpmyadmin/,usertemp_test ,pass: test_temp

我还在构建整个东西,但我还没有填写所有值,比如top_style,pants_style等,所以测试场景的更合适的查询将是:

在哪里:

SELECT `albums_2015`.`filename`, 
       `albums_2015`.`id`, 
       `obstacle_time` 
FROM   `albums_2015` 
WHERE  `albums_2015`.`eventid` = 1 
       AND `album` LIKE '%' 
       AND `obstacle_time` >= '08:00:00' 
       AND `obstacle_time` <= '14:11:10' 
       AND `filename` IN (SELECT `filename` 
                          FROM   `keywords_2015` 
                          WHERE  eventid = 1 
                                 AND 
               `bibnumbers` REGEXP '[[:<:]]113[[:>:]]|[[:<:]]106[[:>:]]') 
ORDER  BY `obstacle_time` 
LIMIT  0, 10 

LEFT JOIN

SELECT `albums_2015`.`filename`,`albums_2015`.`id`,`obstacle_time`
    FROM `albums_2015`
        LEFT JOIN `keywords_2015`
        ON `keywords_2015`.`eventid` = `albums_2015`.`eventid`
            AND `albums_2015`.`filename` = `keywords_2015`.`filename`
    WHERE
        `albums_2015`.`eventid` = 1
        AND `album` LIKE '%'
        AND `obstacle_time` >= '08:00:00'
        AND `obstacle_time` <= '14:11:10'

        AND `bibnumbers` REGEXP '[[:<:]]113[[:>:]]|[[:<:]]106[[:>:]]'

    ORDER BY `obstacle_time`
    LIMIT 0, 10

更多一些提示:

  • 如果你必须处理多表查询,加入使用索引是最好的,

不要介意添加一些索引来加速你的查询(索引占用空间,但在INT字段上它没什么,你获得的收益远远超过你的损失)。


  • 在大表的情况下,缓存远程表中的数据通常是个好主意。

TAG_table上的插入触发器用于缓存远程表格中显示的部分(如专辑概述的标记名称),可帮助您将连接查询保持在下降频率。


  • 注意REGEX ,它会严重伤害穿孔 添加新表以分割数据是一个更好的主意(并使用索引,这是本机优化)

  • 对于大而频繁查询的WHERE子句中的每个字段,您应该有一个索引。 如果你不能放一个,那么你的数据库模型就可以了,需要更改。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM