A. mysql sql优化之 优化GROUP BY 和 DISTINCT
创建表tb_point 表
准备空的tb_box表
函数
编写存储过程,给tb_box表添加100万条数据
修改关联数据
好于
优于
在执行以下语句时会报错:
前面在 https://www.jianshu.com/p/95e50fd017ea 文章中有提到这个问题,是直接修改sql_mode将 ONLY_FULL_GROUP_BY直接干掉。但是在《高性能mysql》中有一段话是这样的:
那么既然指出不要直接修改 sql_mode,那么我们应该如何让冲突的GRUOPBY语句正确执行呢?
文中有提到,可以使用max()和min()函数来实现;但是这种方式使用max和min函数较真的人可能会说这样写的分组查询有问题,确实如此。但是如果更加在乎查询效率,这样做也无可厚非。
如果,实在无法接受使用上面那种方式的话,可以这样使用子查询的方式来进行查询:
书上对于这种方式有描述如下:
这样写更满足关系理论,但是成本有点高,因为子查询需要填充临时表,而子查询中创建的临时表是没有任何索引的。
作者认为这样写对性能有影响。
但是从我测得结果来看,子查询的耗时反而更少。性能反而更佳。这个子查询耗时0.4秒。而使用max方式耗时0.8秒。几乎一倍。我的mysql版本是 5.7.22-log
为了解其中的原因,我们查看它的执行计划:
可见,因为子查询而产生了一层 DERIVED 临时表,但是这个临时表的Extra字段有显示 Using index、key里面显示自建索引。说明用到了索引。这是查询性能可观的一个重要原因吧;
另外我分别使用 SHOW PROFILE命令查看各部分耗时,对比之下。没看到有哪部分耗时差别特别大,使用JOIN、MAX 耗时比上子查询耗时都差不多是1倍
有些时候对一没有建立索引的字段,进行GRUOP BY时。会产生Using filesort 文件内排序。因为GRUOP BY是在排序的基础上进行分组的。
如下面sql:
如果业务上不对排序有要求。那么就可以禁止GRUOP BY的排序:
这样就把Using filesort给干掉了! 执行时间 1.237
当然,多数情况是多排序有要求的。此时也可以在GRUOP BY后面使用DESC和ASC关键字,使分组的结果集按需要的方向排序。如下:
分组查询的一个变种就是要求mysql对分组结果再进行一次超级聚合。可以使用GROUP BY WITH ROLLUP 来实现这种逻辑,但可能性能不佳。因为通过查询计划分析出它是使用 Using temporary; Using filesort 来实现的。
使用WITH ROLLUP,查询时间2.531秒。不使用0.774 秒。
1、所以,很多时候。我们在应用程序中做超级聚合是最好的!
2、当然也可使用UNION ALL 来实现:
3、还可以通过FROM子句嵌套使用子查询:
B. SqlServer2005中 distinct关键字的使用
显示重复记录,还是有重复时只显示一条
如:
--> --> (Roy)生成测试数据
if not object_id('Tempdb..#T') is null
drop table #T
Go
Create table #T([ID] int,[Name] nvarchar(1),[Memo] nvarchar(2))
Insert #T
select 1,N'A',N'A1' union all
select 2,N'A',N'A2' union all
select 3,N'A',N'A3' union all
select 4,N'B',N'B1' union all
select 5,N'B',N'B2'
Go
--I、Name相同ID最小的记录(推荐用1,2,3),方法3在SQl05时,效率高于1、2
方法1:
Select * from #T a where not exists(select 1 from #T where Name=a.Name and ID<a.ID)
方法2:
select a.* from #T a join (select min(ID)ID,Name from #T group by Name) b on a.Name=b.Name and a.ID=b.ID
方法3:
select * from #T a where ID=(select min(ID) from #T where Name=a.Name)
方法4:
select a.* from #T a join #T b on a.Name=b.Name and a.ID>=b.ID group by a.ID,a.Name,a.Memo having count(1)=1
方法5:
select * from #T a group by ID,Name,Memo having ID=(select min(ID)from #T where Name=a.Name)
方法6:
select * from #T a where (select count(1) from #T where Name=a.Name and ID<a.ID)=0
方法7:
select * from #T a where ID=(select top 1 ID from #T where Name=a.name order by ID)
方法8:
select * from #T a where ID!>all(select ID from #T where Name=a.Name)
方法9(注:ID为唯一时可用):
select * from #T a where ID in(select min(ID) from #T group by Name)
--SQL2005:
方法10:
select ID,Name,Memo from (select *,min(ID)over(partition by Name) as MinID from #T a)T where ID=MinID
方法11:
select ID,Name,Memo from (select *,row_number()over(partition by Name order by ID) as MinID from #T a)T where MinID=1
生成结果:
/*
ID Name Memo
----------- ---- ----
1 A A1
4 B B1
C. sql中,只使用union和先union all再distinct,两种方式哪个效率高
Distinct可以说是数据查询中最耗时最耗性能的操作了,去重统计是数据查询不可言说的痛,所以不到万不得已不要用,另外,union all 后在distinct的效率如果更高的话,那union存在的意义是什么?所以可想而知,union的效率更高啊
D. sqlserver 用distinct和group by哪个效率高
sql server数据库进行查询语句时,distinct和group by的效率比较,group by的效率更高一点,因为group by通过group进行排序而distinct是全表排序资源消耗更多。所以,group by效率更高。
E. SQL语句查询 如何删除重复多余的数据
这个是SQL中distinct的典型用法:
1)从字面意思就可以了解到:
distinct
[dis'tiŋkt]
adj.
明显的;独特的;清楚的;有区别的
2)在SQL中用distinct来消除重复出现的
字段
值。
使得每个字段值只出现一次。
具体用法如下:
select
distinct
字段名
from
表;
distinct
字段名
意思就是只显示一次该字段名
一般情况下和order
by
结合使用,这样可以提高效率。
所以这个问题的答案是:select
distinct
1,2,3,4
from
表;
1,2,3,4分别代表第一,二,三,四列的字段名,我猜测可能第一列就是每个人的ID,
这样你把重复的ID过滤留下一个,估计就是你想要的结果了。
希望我的回答能让您满意。
F. SQL中distinct的用法是什么
在表中,可能会包含重复值。这并不成问题,不过,有时您也许希望仅仅列出不同(distinct)的值。关键词 distinct用于返回唯一不同的值。
表A:
返回的结果为两行,这说明distinct并非是对xing和ming两列“字符串拼接”后再去重的,而是分别作用于了xing和ming列。
3.COUNT统计
select count(distinct name) from A; --表中name去重后的数目, SQL Server支持,而Access不支持
count是不能统计多个字段的,下面的SQL在SQL Server和Access中都无法运行。
select count(distinct name, id) from A;
若想使用,请使用嵌套查询,如下:
select count(*) from (select distinct xing, name from B) AS M;
4.distinct必须放在开头
select id, distinct name from A; --会提示错误,因为distinct必须放在开头
5.其他
distinct语句中select显示的字段只能是distinct指定的字段,其他字段是不可能出现的。例如,假如表A有“备注”列,如果想获取distinc name,以及对应的“备注”字段,想直接通过distinct是不可能实现的。但可以通过其他方法实现关于SQL Server将一列的多行内容拼接成一行的问题讨论
G. sql语句去重distinct方法是什么
sql语句去重distinct方法是根据name和id两个字段来去重的。这种方式Access和SQLServer同时支持,返回的结果为两行,这说明distinct并非是对xing和ming两列字符串拼接后再去重的,而是分别作用于了xing和ming列。
sql语句去重distinct特点
distinct语句中select显示的字段只能是distinct指定的字段,其他字段是不可能出现的,例如假如表A有备注列,如果想获取distincname,以及对应的备注字段想直接通过distinct是不可能实现的,但可以通过其他方法实现关于SQLServer将一列的多行内容拼接成一行的问题讨论。
distinct这个关键字用来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是用它来返回不重记录的所有值。其原因是distinct只有用二重循环查询来解决,而这样对于一个数据量非常大的站来说,无疑是会直接影响到效率的。