sql优化:通过子查询或自己的查询计算所有行/其他改进
Posted
技术标签:
【中文标题】sql优化:通过子查询或自己的查询计算所有行/其他改进【英文标题】:sql optimization: count all rows through subquery or own query / other improvements 【发布时间】:2018-07-30 08:58:45 【问题描述】:我正在尝试改进我的 mysql 查询。起初我试图优化那个简单的:
SELECT * ,
(
SELECT COUNT(id)
FROM animal
WHERE type = :type AND timestampadopt > 0 AND (date BETWEEN DATE_FORMAT(CURDATE() , '%Y-%m-%d') - INTERVAL 1 YEAR AND DATE_FORMAT(CURDATE(),'%Y-%m-%d'))
) AS countanimals
FROM animal
WHERE type = :type AND timestampadopt > 0 AND (date BETWEEN DATE_FORMAT(CURDATE() , '%Y-%m-%d') - INTERVAL 1 YEAR AND DATE_FORMAT(CURDATE(),'%Y-%m-%d'))
ORDER BY timestamp DESC
LIMIT 1, 20;
列:
id | timestampadd | timestampadopt | dateborn | animaltype | gender | chipped | smalldescger | smalldesceng | imagepath
在受影响的网站上,我循环播放所有动物,并进行分页。所以你可以看到 20 只动物,接下来的 20 只你必须使用下一步按钮。
我需要知道分页需要显示多少个站点,所以我必须计算总共有多少动物,这就是子查询的作用。
我通过分析时间来测量并得到以下结果:
0.0047s 用于总查询,0.0023s 用于子查询
在数据库中只有 5 行!
在那个网站上,我提供了一些过滤器,比如年龄 +/- 1 岁,并且是已经采用的动物,因此我需要在两者上都使用 WHERE 子句,这可能会占用最多的性能,然后是 order by 子句这是首先显示新的所必需的。
附:我需要表中的所有列,我做了一些测试,SELECT *
具有相同的运行时间,然后像某些人推荐的那样手动选择所有 10 列。
编辑: 是否值得在自己的表中排除 smalltext (varchar 250)、imagpath (varchar 50) 列并将它们内部连接起来,其他列我可能需要稍后过滤。但是类型、性别、碎片是微小的。
对我有什么改进建议吗?
我应该在主查询之外的自己的查询中执行子查询吗?
编辑:31.07
SELECT a.* , c.cnt AS countanimals
FROM animal a
JOIN (
Select a1.date AS date1, a1.tmstmpadopt AS tmstmpadopt1, a1.type AS type1, COUNT(a1.id) as cnt
FROM animal a1
GROUP BY date1, tmstmpadopt1, type1
) c on (a.date = c.date1 AND a.tmstmpadopt = c.tmstmpadopt1 AND a.type = c.type1)
WHERE a.type = 1 AND tmstmpadopt = 0 AND (date BETWEEN DATE_FORMAT(CURDATE() , '%Y-%m-%d') - INTERVAL 100 YEAR AND DATE_FORMAT(CURDATE(),'%Y-%m-%d')- INTERVAL 1 YEAR)
ORDER BY a.timestamp DESC
LIMIT 1, 20;
【问题讨论】:
【参考方案1】:内联视图可能会对您有所帮助。所以试试这个
SELECT a.*,c.cnt AS countanimals
FROM animal a
join (Select a1.dateborn, a1.timestampadopt, count(a1.id) as cnt
from animals a1
Where a1.timestampadopt > 0
and a1.type = :type
group by a1.dateborn, a1.timestampadopt) c on (a.dateborn = c.dateborn and a.timestampadopt = c.timestampadopt)
WHERE a.type = :type
AND a.timestampadopt > 0
AND a.dateborn BETWEEN DATE_FORMAT(CURDATE(),'%Y-%m-%d')-INTERVAL 1 YEAR AND DATE_FORMAT(CURDATE(),'%Y-%m-%d'))
ORDER BY a.timestamp DESC
LIMIT 1, 20;
【讨论】:
太好了,它看起来已经相当快了〜20%,也许行数更多,差异会更大。那是因为日期行上的 join 或 group by 吗?我可以按类型和时间分组以获得更好的结果吗? 我在该内联视图中添加了 timestampadopt。现在它不应该有任何区别。如果仍然显示差异,请发布一些示例数据 我的意思是删除连接中的“a1.timestampadopt > 0”,并像在 a1.dateborn 上那样使用 group by。在这种情况下,分组比在哪里或加入会有所不同吗?因为我们已经在主查询中调用了“where a1.timestamppadopt > 0”。 不,我们应该添加该条件,然后只会减少数据量,因为您只需要 timestampadopt > 0 的所有记录。我在 select 和 group by 子句中添加了 timestampadopt,并在子句 a.timestampadopt.= c.timestampadopt 中添加了相同的内容。它会自动过滤 是的,这是正确的。聚合的一般经验法则过滤掉不需要的记录,然后对数据进行分组【参考方案2】:您为什么不对脚本进行计数,当您处理行时,您可以计算它们。
【讨论】:
由于站点限制(限制 $start,$end),我无法计算所有行。结果我只得到20行。但我需要所有行来计算分页。我编辑了这个问题,所以现在更清楚了;D.以上是关于sql优化:通过子查询或自己的查询计算所有行/其他改进的主要内容,如果未能解决你的问题,请参考以下文章