MySQL 检索数据及提高检索速度的方法

检索数据

mysql> SELECT [DISTINCT] 表名.列名,表名.列名,表名.列名  -- 使用通配符*表示所有列  DISTINCT表示返回不同的值
-> FROM 数据库名.表名 -- 使用全限定名
-> WHERE 筛选条件 [AND|OR] 筛选条件;
-> ORDER BY 列名 [ASC|DESC], 列名 [ASC|DESC], --先按第一列排序,再按第二列排序
-> LIMIT 行数 OFFSET 起始行;

WHERE字句操作符

-- 字符串用单引号,数值不用
= --相等 可用于数值和字符串
<> --不相等 可用于数值和字符串
!= --不相等 可用于数值和字符串
< -- 小于 可用于数值和字符串
<= -- 小于等于 可用于数值和字符串
> -- 大于 可用于数值和字符串
>= -- 大于等于 可用于数值和字符串
[NOT] BETWEEN 开始值 AND 结束值 -- 指定两个值之间,包括开始值和结束值 可用于数值和字符串 能用between尽量不用in
[NOT] LIKE '字符串' --配合通配符使用,%表示任何字符出现任意次数; _表示只匹配一个字符
[NOT] IN (值1, 值2, ...) -- 取合法值由逗号分隔的清单,全部括在圆括号中。IN操作符比OR操作符更快
[NOT] EXISTS --
IS [NOT] NULL -- 检查空值

正则表达式匹配

--LIKE只能匹配整个字符串,REGEXP可以匹配字串; '^字符串$'使得REGEXP的作用与LIKE一样
[NOT] REGEXP '字符串';
. --表示匹配任意一个字符
* --表示0个或多个匹配
+ --表示1个或多个匹配
? --表示0个或1个匹配
^ --表示文本的开始
$ --表示文本的结束
[[:<:]] --表示词的开始
[[:>:]] --表示词的结束
| --表示匹配两个串之一
[] --表示匹配括弧中字符中的单个字符
[ - ] --表示在匹配某个范围类的单个字符
\\ --转义字符
{n} --表示
{n,} --表示
{n,m} --表示

检索结果去重复 DISTINCT()

distinct(str) 函数是用来去掉重复记录的,但是它只是针对某一个字段可以去重复

select distinct(name) from user;

如果要查询不重复的记录,有时候可以用到 group by

select id, name from users group by name

UNION 操作符 连接两个以上的 select 语句的结果到一个结果集合中

select 列1, 列2, 列3 from tables [where condition]
union [all | distinct]
select 列1, 列2, 列3 from tables [where condition];
-- UNION ALL 返回所有结果集,包括重复数据
-- UNION 或 UNION DISTINCT 效果一样,会在最终的结果集中删除重复数据

ORDER BY 对检索结果进行排序

select 列1, 列2, 列3 from tables where conditions order by 列1, 列2 [ASC|DESC];
-- ASC 是升序排列,DESC是降序排列,默认为ASC
-- 可是设置多个排序列,如上先按列1排序,然后再按列2排序

GROUP BY 对检索结果进行分组 通常配合聚合函数使用

提高 MySQL 检索速度的方法

尽量使用索引,尽量避免全表扫描

1. 应尽量避免在 where 子句中使用 <> 或 != 操作符,否则将使引擎放弃使用索引而进行全表扫描。

2. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 设计的列上建立索引。

3. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。

如 select id from  t where num is null;

可以在 num 列上设置默认值 0, 确保表中 num 列中没有 null 值,然后这样查询

select id from t where num = 0;

4. 尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描。

如 select id from t where num = 10 or num = 20

可以这样查询

select id from t where num = 10

union all

select id from t where num = 20;

5. 下面的查询也将导致全表扫描,应尽量避免,不能前置百分号。

如 select id from table where name like '%c%';

若要提高效率,可以考虑进行全文检索。

6. in 和 not in 也要慎用,否则会导致全表扫描。

如 select id from t where num in (1, 2, 3);

对于连续的数值,能用 between 就不要用 in 了。

如 select id from t where num between 1 and 3;

7. 如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时,它必须在编译时进行选择。然而如果在编译时进行访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。

如下面的语句将进行全表扫描

select id from t where num=@num;

可以改为强制查询使用索引

select id from t with(index(索引名)) where num=@num;

8. 尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃索引而进行全表扫描。

如 select id from t where num/2 = 100;

应该为

select id from t where num = 100*2;

9. 尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。

如 select id from t where substring(name, 1, 3) = 'abc'  -- 搜索 name 以 ‘abc’ 开头的行

select id from t where datediff(createdate, '2005-11-30') = 0    -- 搜索 createdate 为 2005-11-30 的行

应该为

select id from t where name like 'abc%';

select id from t where createdate >= '2005-11-30' and createdate < '2005-12-1';

10. 不要在 where 子句中的 = 左边进行函数、算数运算或者其他表达式运算,否则系统将可能无法正确使用索引。

11. 在使用组合索引时,必须使用到该索引中的第一个字段作为条件时,才能保证系统使用组合索引。否则组合索引不会被使用,并且尽可能的让字段顺序与索引顺序相一致。

12. 不要写一些没有意义的查询。

如需要生成一个空表结构

select col1, col2 into #t from t where 1=0;

这类代码不会返回任何结果集,但是会消耗系统资源,应改成:

create table #t(...)

13. 很多时候用 exists 代替 in 是一个好的选择。

如 select num from t where num in (select num from b);

可用下面的语句替换

select num from t where exists(select 1 from b where num = t.num);

14. 并不是所有索引对查询都有效,SQL是根据表中的数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引。

如对于表中的 gender 字段,可能 male 和 female 各一半,这时即使在 gender 上建立了索引对查询效率也起不了作用。

15. 索引并非越多越好,索引在提高 select 效率的同时,也会降低 insert 和 update 的效率,因为进行 insert 和 update 操作时可能会重建索引。

16. 尽量避免更新聚簇索引(clustered index)数据列,因为聚簇索引数据列的顺序就是表技术的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。

17. 尽量使用数字型字段,对于只含数字信息的字段尽量不要涉及为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中的每一个字符,而对于数字型而言只需要比较一次就够了。

18. 尽量使用 varchar / nvarchar 代替 char / nchar,因为变长字段存储空间小,可以节省存储空间;另外对于查询而言,在一个相对较小的字段内搜索效率显然要高些。

19. 任何地方不要使用 select * from t; 而是用具体的字段名称代替“*”,不要返回用不到的任何字段。

20. 尽量使用表变量来代替临时表,如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。

21. 避免频繁创建和删除临时表,以减少系统表资源的消耗。

22. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 语句代替 create table 语句,避免造成大量 log,以提高速度,如果数据量不大,为了缓和系统表资源,应先 create table, 然后 insert。

23. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显示删除,先 truncate table, 然后 drop table,这样可以避免系统该表的较长时间锁定。

24. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。但是对于小型数据集,使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需数据。

25. 会用基于游标的方法或者临时表方法前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

26. 在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON, 在结束时设置 SET NOCOUNT OFF。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。

27. 尽量避免像客户端返回大量数据,若数据量过大,应该考虑需求是否合理。

28. 尽量避免大事务操作,提高系统并发能力。

待续...

上一篇:python中open函数的用法


下一篇:用C表达面向对象语言的机制——C#版