1、选取最适用的字段属性
一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。
例如,在定义邮政编码这个字段时,如果将其设置为CHAR(255),显然给数据库增加了不必要的空间,甚至使用VARCHAR这种类型也是多余的,因为CHAR(6)就可以很好的完成任务了。同样的,如果可以的话,我们应该使用MEDIUMINT而不是BIGIN来定义整型字段。
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库.
备注、描述、评论之类的可以设置为 NULL,其他的,最好不要使用NULL。
不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间就固定了, 不管是否插入值(NULL也包含在内),都是占用 100个字符的空间的,如果是varchar这样的变长字段, null 不占用空间。
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num = 0
3.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or Name = 'admin'
可以这样查询:
select id from t where num = 10 union all select id from t where Name = 'admin'
4、使用索引
索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有MAX(),MIN()和ORDERBY这些命令的时候,性能提高更为明显。
那该对哪些字段建立索引呢?
一般说来,索引应建立在那些将用于JOIN,WHERE判断和ORDERBY排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。对于一个ENUM类型的字段来说,出现大量重复值是很有可能的情况
例如customerinfo中的“province”..字段,在这样的字段上建立索引将不会有什么帮助;相反,还有可能降低数据库的性能。我们在创建表的时候可以同时创建合适的索引,也可以使用ALTERTABLE或CREATEINDEX在以后创建索引。此外,MySQL从版本3.23.23开始支持全文索引和搜索。全文索引在MySQL中是一个FULLTEXT类型索引,但仅能用于MyISAM类型的表。对于一个大的数据库,将数据装载到一个没有FULLTEXT索引的表中,然后再使用ALTERTABLE或CREATEINDEX创建索引,将是非常快的。但如果将数据装载到一个已经有FULLTEXT索引的表中,执行过程将会非常慢。
5.用EXISTS替代IN、用NOT EXISTS替代 NOT IN:
在基于基础表的查询中经常需要对另一个表进行联接。在这种情况下, 使用EXISTS(或NOT
EXISTS)通常将提高查询的效率。在子查询中,NOT IN子句将执行一个内部的排序和合并。无
论在哪种情况下,NOT IN都是最低效的(要对子查询中的表执行了一个全表遍历)。所以尽量将
NOT IN改写成外连接(Outer Joins)或NOT EXISTS。
(高效)
-
SELECT A.* FROM TEMP(基础表) A WHERE AGE > 0
-
AND EXISTS(SELECT 1 FROM TEMP1 WHERE A.ID= ID AND NAME='TOM');
(低效)
-
SELECT A.* FROM TEMP(基础表) A WHERE AGE > 0
-
AND A.ID IN(SELECT ID FROM TEMP1 WHERE NAME ='TOM');
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)
6.善用explain:
看看自己写的sql到底要涉及到多少表,多少行,使用了那些索引,根据这些信息适当的创建索引;
7.SELECT子句中避免使用 * :
ORACLE在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字
典完成的, 这意味着将耗费更多的时间。
8.使用表的别名(Alias):
当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上。这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误。 Chinaz_com
9.删除重复记录:
最高效的删除重复记录方法 :
-
DELETE FROM TEMP E
-
WHERE E.ROWID > (SELECT MIN(X.ROWID)
-
FROM TEMP1 X WHERE X.TEMP_NO = E.TEMP_NO);
10.根据需要用UNION ALL替换UNION:
当SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并,
然后在输出最终结果前进行排序。如果用UNION ALL替代UNION, 这样排序就不是必要了。
效率就会因此得到提高。需要注意UNION ALL将重复输出两个结果集合中相同记录。因此要
从业务需求使用UNION ALL的可行性。UNION 将对结果集合排序,这个操作会使用到
SORT_AREA_SIZE这块内存。对于这块内存的优化也很重要。
低效:
-
SELECT USER_ID,BILL_ID FROM USER_TAB1 WHERE AGE = '20'
-
UNION
-
SELECT USER_ID,BILL_ID FROM USER_TAB2 WHERE AGE = '20';
-
SELECT USER_ID,BILL_ID FROM USER_TAB1 WHERE AGE = '20'
-
UNION ALL
-
SELECT USER_ID,BILL_ID FROM USER_TAB2 WHERE AGE = '20';
11.用TRUNCATE替代DELETE:
当删除表中的记录时,在通常情况下, 回滚段(rollback segments)用来存放可以被恢复的
信息。如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执
行删除命令之前的状况)。而当运用TRUNCATE时,回滚段不再存放任何可被恢复的信息。当命
令运行后,数据不能被恢复。因此很少的资源被调用,执行时间也会很短。
注:TRUNCATE只在删除全表适用,TRUNCATE是DDL不是DML。
12.查'低效执行'的SQL语句:
SELECT EXECUTIONS,DISK_READS,BUFFER_GETS,
ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) HIT_RADIO,
ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,SQL_TEXT
FROM V$SQLAREA
WHERE EXECUTIONS > 0 AND BUFFER_GETS > 0
AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY 4 DESC;