我需要一条建议,现在构建一个应用程序,我需要在相当大的表上运行一些查询,可能是非常频繁的,所以我正在努力获得最佳的性能方法。
我有以下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查询将返回下一个图像块)。 / p>
现在我的问题是,以下哪个查询的性能更好:
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
或使用IN
内的WHERE
条款,如:
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/,用户: temp_test ,传递: 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
答案 0 :(得分:2)
更多一些提示:
不要介意添加一些索引来加快查询速度(索引占用空间,但在INT
字段上它没什么,你获得的收益远远超过你的损失。)
TAG_table
上的插入触发器,用于缓存远程表格中显示的部分(如相册概览的标记名称),可帮助您将联接查询保持在下降频率。
REGEX
,严重伤害了。添加新表以分割数据是一个更好的主意(并使用索引,这是本机优化)WHERE
子句中的每个字段,您应该有一个索引。如果你不能放一个,那么你的数据库模型就可以了,需要更改。