如何优化SQL

更新时间:2024-05-17 03:51:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

在一个千万级的数据库查寻中,如何提高查询效率?

2015-03-10 0 个评论 来源:徐刘根的专栏

收藏

我要投稿

在一个千万级的数据库查寻中,如何提高查询效率? 1)数据库设计方面:

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

b. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0

c. 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。

d. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

e. 应尽可能的避免更新索引数据列,因为索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新索引数据列,那么需要考虑是否应将该索引建为索引。

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

g. 尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

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

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

j. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。

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

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

2)SQL语句方面:

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

b. 应尽量避免在 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

c. 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

d. 下面的查询也将导致全表扫描: select id from t where name like ‘?c%’ e. 如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描: select id from t where num=@num 可以改为强制查询使用索引: select id from t with(index(索引名)) where num=@num

f. 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如: select id from t where num/2=100 应改为: select id from t where num=100*2

g. 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如: select id from t where substring(name,1,3)=’abc’–name以abc开头的id select id from t where datediff(day,createdate,’

2005-11-30′)=0–‘2005-11-30’生成的id 应改为: select id from t where name like ‘abc%’ select id from t where createdate>=’2005-11-30′ and createdate<’2005-12-1′

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

i. 不要写一些没有意义的查询,如需要生成一个空表结构: select col1,col2 into #t from t where 1=0 这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: create table #t(?)

j. 很多时候用 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)

k. 任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。

l. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。

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

n. 尽量避免大事务操作,提高系统并发能力。 3)java方面:重点内容 a.尽可能的少造对象。

b.合理摆正系统设计的位置。大量数据操作,和少量数据操作一定是分开的。大量的数据操作,肯定不是ORM框架搞定的。,

c.使用jDBC链接数据库操作数据

d.控制好内存,让数据流起来,而不是全部读到内存再处理,而是边读取边处理;

e.合理利用内存,有的数据要缓存 如何优化数据库,如何提高数据库的性能? 解答:

1) 硬件调整性能 最有可能影响性能的是磁盘和网络吞吐量,解决办法扩大虚拟内存,并保证有足够可以扩充的空间;把数据库服务器上的不必要服务关闭掉;把数据库服务器和主域服务器分开;把SQL数据库服务器的吞吐量调为最大;在具有一个以上处理器的机器上运行SQL。

2)调整数据库

若对该表的查询频率比较高,则建立索引;建立索引时,想尽对该表的所有查询搜索操作, 按照where选择条件建立索引,尽量为整型键建立为有且只有一个簇集索引,数据在物理上按顺序在数据页上,缩短查找范围,为在查询经常使用的全部列建立非簇集索引,能最大地覆盖查询;但是索引不可太多,执行UPDATE DELETE INSERT语句需要用于维护这些索引的开销量急剧增加;避免在索引中有太多的索引键;避免使用大型数据类型的列为索引;保证每个索引键值有少数行。

3)使用存储过程

应用程序的实现过程中,能够采用存储过程实现的对数据库的操作尽量通过存储过程来实现,因为存储过程是存放在数据库服务器上的一次性被设计、编码、测试,并被再次使用,需要执行该任务的应用可以简单地执行存储过程,并且只返回结果集或者数值,这样不仅可以使程序模块化,同时提高响应速度,减少网络流量,并且通过输入参数接受输入,使得在应用中完成逻辑的一致性实现。

4)应用程序结构和算法

建立查询条件索引仅仅是提高速度的前提条件,响应速度的提高还依赖于对索引的使用。因为人们在

使用SQL时往往会陷入一个误区,即太关注于所得的结果是否正确,特别是对数据量不是特别大的数据库操作时,是否建立索引和使用索引的好坏对程序的响应速度并不大,因此程序员在书写程序时就忽略了不同的实现方法之间可能存在的性能差异,这种性能差异在数据量特别大时或者大型的或是复杂的数据库环境中(如联机事务处理OLTP或决策支持系统DSS)中表现得尤为明显。在工作实践中发现,不良的SQL往往来自于不恰当的索引设计、不充份的连接条件和不可优化的where子句。在对它们进行适当的优化后,其运行速度有了明显地提高!

classProgram

{

staticvoid Main(string[] args) {

int[] letters = newint[26]; // 用于保存大写字符出现的数量

int[] letters1 = newint[26]; // 用于保存小写字符出现的数量 stringstr = string.Empty; char c;

//for (inti = 0; i< 26; i++) // letters[i] = new int();

str = Console.ReadLine().Trim(); // 读入一行字符串

for (inti = 0; i

c = Convert.ToChar(str.Substring(i, 1)); if (c >= 65 && c <= 90) // 大写 letters[c - 65]++; elseif (c >= 97 && c <= 122) // 小写 letters1[c - 97]++; }

// 打印结果

Console.WriteLine(\字母\\t次数\); for (c = 'A'; c <= 'Z'; c++) {

if (letters[c - 65] > 0) Console.WriteLine(\, c, letters[c - 65]); }

for (c = 'a'; c <= 'z'; c++) {

if (letters1[c - 97] > 0) Console.WriteLine(\, c, letters1[c - 97]); }

Console.ReadKey(true); }

}

简单工厂模式和工厂方法模式

2013-01-10 21:15 7152人阅读 评论(3) 收藏 举报

分类:

设计模式(7)

版权声明:本文为博主原创文章,未经博主允许不得转载。

目录(?)[+]

一:简单工厂模式

1,概念

简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。顾名思义工厂就是生产东西的,有原料(参数),模子(对象)就能生产出很多个具有相同功能的对象啦。 2,uml图

3,代码示例

[csharp] view plain copy print?

1. class Program 2. {

3. static void Main(string[] args) 4. {

5. Operate oper; //创建Operate类的oper类

6. oper = OperationFactoty.createOperate(\); //运用简单工厂判断实力

化的对象

7. oper.NumberA = 1; //赋值 8. oper.NumberB = 2;

9. double result = oper.GetResult();

10. Console.WriteLine(result); //显示运算结果 11. } 12. } 13.

14. //简单工厂,通过判断参数,实例化相应的对象 15. public class OperationFactoty 16. {

17. public static Operate createOperate(string operate) 18. {

19. Operate oper = null; 20. switch (operate){ } 21. return oper; 22. } 23. } 24.

25. //定义一个运算基类,包含GetResult虚方法 26. public class Operate //定义一个运算类 27. {

28. private double numberA=0; //运算前的数 29. private double numberB=0; //运算后的数 30. public double NumberA{ } 31. public double NumberB{ } 32.

33. public virtual double GetResult()//返回运算后结果的方法 34. {

35. return result; //返回结果 36. } 37. } 38.

39. // 运算类的四个继承类,分别实现加减乘除四个运算 40. public class NumberAdd : Operate //加运算 41. {

42. public override double GetResult()//实现基类中的虚方法 43. {

44. double result = NumberA + NumberB; 45. return result; 46. } 47. }

48. public class NumberSub:Operate //减运算 49. {

50. public override double GetResult(){ }

51. }

52. public class NumberMul:Operate //乘运算 53. {

54. public override double GetResult(){ } 55. }

56. public class NumberDiv:Operate //除运算 57. {

58. public override double GetResult(){ } 59. }

4,总结

简单工厂模式,我把它理解为一个模子,根据外界给定的原料,在加上自身封装好的判断,生产出不同类型的相应的产品、对象。

简单工厂模式使用场景:工厂类负责创建的对象比较少;客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心;简单工厂很容易违反高内聚低耦合原则,因此一般只在很简单的情况下应用。

二:工厂方法模式

1,概念

是定义一个创建产品对象的工厂接口,让子类决定实例化哪一个类,将实际创建工作推迟到子类当中。

2,uml图

3,代码实例

(1)工厂方法实现

[csharp] view plain copy print?

1. class Program 2. {

3. static void Main(string[] args) 4. {

5. IFactory factory = new UndergraduateFactory(); //由接口创建新的

学雷锋大学生

6. LeiFeng student = factory.CreateLeifeng(); //实例化 7.

8. student.BuyRice(); 9. student.Sweep(); 10. student.Wash(); 11. } 12. }

13. //雷锋类,定义了一些功能 14. class LeiFeng 15. {

16. public void Sweep(){ } //擦桌子 17. public void Wash(){ } //洗衣服

18. public void BuyRice(){ } //买米 19. } 20. 21.

22. //学雷锋的大学生

23. class UnderGraduate : LeiFeng{ } 24. //社区志愿者

25. class Volunteer : LeiFeng{ } 26.

27. //雷锋工厂

28. interface IFactory //定义一个接口,实现创建雷锋类的功能 29. {

30. LeiFeng CreateLeifeng(); 31. } 32.

33. class UndergraduateFactory : IFactory//学雷锋大学生工厂 34. {

35. public LeiFeng CreateLeiFeng() 36. {

37. return new UnderGraduate(); 38. } 39. }

40. class VolunteerFactory : IFactory//社区志愿者工厂 41. {

42. public LeiFeng CreateLeiFeng() 43. {

44. return new Volunteer(); 45. } 46. }

(2)简单工厂实现

[csharp] view plain copy print?

1. class Program 2. {

3. static void Main(string[] args) 4. {

5. LeiFeng studentA = SimpleFactory.CreateLeiFeng(\学雷锋的大学生

\);//用简单工厂创建并实例化学雷锋的大学生 6. studentA.BuyRice();

7. LeiFeng studentB = SimpleFactory.CreateLeiFeng(\社区志愿者\);//用

简单工厂创建实例化社区志愿者 8. studentB.BuyRice(); 9. } 10. }

11. //雷锋类,定义了一些功能 12. class LeiFeng 13. {

14. public void Sweep(){ } //擦桌子 15. public void Wash(){ } //洗衣服 16. public void BuyRice(){ } //买米 17. } 18. 19.

20. //简单工厂类

21. class SimpleFactory 22. {

23. public static LeiFeng CreateLeiFeng(string type) 24. {

25. LeiFeng result = null;

26. switch (type) //判断选择要创建对象的类型 27. {

28. case \学雷锋的大学生\:

29. result = new UnderGraduate(); 30. break; 31. case \社区志愿者\:

32. result = new UnderGraduate(); 33. break; 34. }

35. return result; 36. } 37.

38. }

4,总结

工厂方法模型中,“工厂”创建的是还没有分化好的对象,其中没有逻辑判断相比于简单工厂模式,基类工厂去实现接口,子工厂去实现判断并能生产出相应功能的对象。

三:简单工厂和工厂方法模式的比较

1,简单工厂模式

专门定义一个工厂类负责创建其他类的实例,最大的优点在于工厂类中包含了必要的逻辑,根据客户需要的条件动态实例化相关的类

2,工厂方法模式

创建对象的接口,让子类去决定具体实例化的对象,把简单的内部逻辑判断移到了客户端代码。工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。

//单链表结点类,采用泛型 public class Node {

private T data; //数据域,当前结点的数据 private Node next; //引用域,即下一结点

//构造器:数据域+引用域,普通结点 public Node(T item, Node p) {

data = item;

next = p; }

//构造器:引用域,头结点 public Node(Node p) {

next = p; }

//构造器:数据域,尾结点 public Node(T val) {

data = val; next = null; }

//构造器:无参数 public Node() {

data = default(T); next = null; }

//数据域属性 public T Data { get {

return data; } set {

data = value; } }

//引用域属性 public Node Next { get {

return next; } set

{

next = value; } } }

//链表类,包含链表定义及基本操作方法 public class MyLinkList {

private Node head; //单链表的头结点

//头结点属性

public Node Head { get {

return head; } set {

head = value; }

}

//构造器

public MyLinkList() {

head = null; }

//求单链表的长度 public intGetLength() {

Node p = head; intlen = 0;

while (p != null) {

++len; p = p.Next; }

return len; }

//清空单链表

public void Clear() {

head = null; }

//判断单链表是否为空 public bool IsEmpty() {

if (head == null) {

return true; } else {

return false; } }

//在单链表的末尾添加新元素 public void Append(T item) {

Node q = new Node(item);

Node p = new Node(); if (head == null) {

head = q; return; } p = head;

while (p.Next != null) {

p = p.Next; } p.Next = q; }

//在单链表的第i个结点的位置前插入一个值为item的结点 public void Insert(T item, inti) {

if (IsEmpty() || i< 1||i>GetLength ()) {

Console.WriteLine(\ return;

} if (i == 1) {

Node q = new Node(item); q.Next = head;

head = q; return; }

Node p = head;

Node r = new Node(); int j = 1;

while (p.Next != null && j

Node q = new Node(item); q.Next = p; r.Next = q;

} }

//在单链表的第i个结点的位置后插入一个值为item的结点 public void InsertPost(T item, inti) {

if (IsEmpty() || i< 1||i>GetLength ()) {

Console.WriteLine(\ return; } if (i == 1) {

Node q = new Node(item); q.Next = head.Next; head.Next = q;

return; }

Node p = head; int j = 1;

while (p != null && j

p = p.Next; ++j; } if (j == i) {

Node q = new Node(item); q.Next = p.Next; p.Next = q; } }

//删除单链表的第i个结点 public T Delete(inti) {

if (IsEmpty() || i< 0 || i>GetLength()) {

Console.WriteLine(\ return default(T); }

Node q = new Node(); if (i == 1) {

q = head; head = head.Next; return q.Data; }

Node p = head; int j = 1;

while (p.Next != null && j

return p.Data; } else {

Console.WriteLine(\ return default(T); }

}

//获得单链表的第i个数据元素 public T GetElem(inti) {

if (IsEmpty() || i< 0) {

Console.WriteLine(\ return default(T); }

Node p = new Node(); p = head; int j = 1;

while (p.Next != null && j

++j; p = p.Next; } if (j == i) {

return p.Data;

} else {

Console.WriteLine(\ return default(T); } }

//在单链表中查找值为value的结点 public int Locate(T value) {

if (IsEmpty()) {

Console.WriteLine(\ return -1; }

Node p = new Node(); p = head; inti = 1;

while (!p.Data.Equals(value) &&p.Next != null) {

p = p.Next;

++i; } return i; }

//显示链表

public void Display() {

Node p = new Node(); p = this.head; while (p != null) {

Console.Write(p.Data+\ p = p.Next; } } }

public class Program {

static void Main(string[] args) {

MyLinkListmyLinkList = new MyLinkList(); //实例化一个单链表 Console.WriteLine(myLinkList.GetLength()); //获取长度

//添加元素 myLinkList.Append(\myLinkList.Append(\myLinkList.Append(\

myLinkList.Insert(\ //在i结点前插元素,位置错误测试 myLinkList.InsertPost(\ //在i结点后插元素,位置错误测试

myLinkList.InsertPost(\ //后插元素 myLinkList.Insert(\ //前插元素

myLinkList.Display(); //显示链表元素

Console.WriteLine(myLinkList.GetElem(4));//获取结点,并显示

myLinkList.Delete(1); //删除结点

myLinkList.Display();

Console.WriteLine(myLinkList.GetLength()); //显示链表长度 Console.Read(); } }

本文来源:https://www.bwwdw.com/article/gwl7.html

Top