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优化:通过子查询或自己的查询计算所有行/其他改进的主要内容,如果未能解决你的问题,请参考以下文章

Mysql JOIN 子查询

通过 LEFT JOIN 优化 SQL 子查询

查询优化,(子查询)(sql-transact)

使用 SQL Server 将子查询结果重用于其他计算

优化具有 While 循环和交叉应用的 T-SQL 查询

SQL语句汇总(三)——聚合函数分组子查询及组合查询 - Darly