大量数据,用数据库好,还是重新设计一种算法用来存储和查找?()

anxing 2003-11-01 09:38:48
在项目中我遇到一个问题:
我们的项目需要对大量的数据进行查找。几万条的记录,而且访问可能很频繁。记录如下格式。
城市 区号 数据
长春 431 431,4315-4319,4400-4419,4480-4489,4490-4499
吉林 432 4320-4329,4420-4429,4460-4469
延吉 433 4335-4339,4430-4439,4332,4470-4478
四平 434 4346-4349,4440-4449,4331
通化 435 43340-43343,43349,4340,4351,4353,4354,4357
白山 439 4342,4390-4399,4314
珲春 440 4479
白城 436 4345,4360-4369
梅河 448 43344-43348,4450,4452,4455-4457,4341,4350,4352,

需要根据'数据'来对应于城市。那么如果采用数据库数据有两种方案:
说明:4315-4319指的是从4315到4319的数据都可以定位到长春。
方案1:
把所以数据录入数据库,如4315-4319录为
长春 431 4315
长春 431 4316
长春 431 4317
...
长春 431 4319
就是把所有表示范围的数据拆开,这样查找算法简单,只是数据库数据量比较大因而查找速度慢。
方案2:
不拆数据录入如下:
长春 431 4315-4319
这样数据记录数会小很多,但是对于每条记录都要解析,如,比如查4316,那么就要对数据进行解析。实际上算法也几乎是不可行的。



不采用数据库,自定一种存储和查找算法,如采用HASH算法,(只是这样说,这种算法还不知是否可行。)

请教高手,我们要怎么做????

几万的数据量,对于sql_server是不是问题?是否能在用SQL的情况下,找一种良好的方法。请教高手。






...全文
246 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
anxing 2003-11-03
  • 打赏
  • 举报
回复
谢了zjcxc(邹建) 。
anxing 2003-11-03
  • 打赏
  • 举报
回复
谢了zjcxc(邹建) 。
zezejun 2003-11-03
  • 打赏
  • 举报
回复
学习
大文 2003-11-01
  • 打赏
  • 举报
回复
用一折中方法
城市 区号 起始 结束
长春 43 15 19
Steve_csdn 2003-11-01
  • 打赏
  • 举报
回复
当然是用数据库,关键看你的设计,你的第二个想法实际就是自己写一个简易的DBMS
zjcxc 元老 2003-11-01
  • 打赏
  • 举报
回复
优化2.

1、要合理使用索引
索引是数据库一个重要的构成部分,很多人都会忽略它,其实索引的根本目的就是
为了提高查询效率。
使用原则如下:
在经常进行连接,但是没有指定为外键的列上建立索引,而不经常连接的字段则
由优化器自动生成索引。

在频繁进行排序或分组(即进行group by或order by操作)的列上建立索引。

在条件表达式中经常用到的不同值较多的列上建立检索,在不同值少的列上不要
建立索引。比如在雇员表的“性别”列上只有“男”与“女”两个不同值,因此就
无必要建立索引。如果建立索引不但不会提高查询效率,反而会严重降低更新速度

如果待排序的列有多个,可以在这些列上建立复合索引(compound index)。

在写sql语句时就必须注意有些写法是会使得数据库无法使用索引的,比如IS NULL
IS NOT NULL,IN ,NOT IN 等。。。

2.避免或简化排序
应当简化或避免对大型表进行重复的排序。当能够利用索引自动以适当的次序产生
输出时,优化器就避免了排序的步骤。以下是一些影响因素:
●索引中不包括一个或几个待排序的列;
●group by或order by子句中列的次序与索引的次序不一样;
●排序的列来自不同的表。
为了避免不必要的排序,就要正确地增建索引,合理地合并数据库表(尽管有时可
能影响表的规范化,但相对于效率的提高是值得的)。如果排序不可避免,那么应
当试图简化它,如缩小排序的列的范围等。

3.消除对大型表行数据的顺序存取
在嵌套查询中,对表的顺序存取对查询效率可能产生致命的影响。比如采用顺序存
取策略,一个嵌套3层的查询,如果每层都查询1000行,那么这个查询就要查询10
亿行数据。避免这种情况的主要方法就是对连接的列进行索引。例如,两个表:学
生表(学号、姓名、年龄……)和选课表(学号、课程号、成绩)。如果两个表要
做连接,就要在“学号”这个连接字段上建立索引。
还可以使用并集来避免顺序存取。尽管在所有的检查列上都有索引,但某些形式的
where子句强迫优化器使用顺序存取。下面的查询将强迫对orders表执行顺序操作

SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR
order_num=1008
虽然在customer_num和order_num上建有索引,但是在上面的语句中优化器还是使
用顺序存取路径扫描整个表。因为这个语句要检索的是分离的行的集合,所以应该
改为如下语句:
SELECT * FROM orders WHERE customer_num=104 AND order_num>1001
UNION
SELECT * FROM orders WHERE order_num=1008
这样就能利用索引路径处理查询。

4.避免相关子查询
一个列的标签同时在主查询和where子句中的查询中出现,那么很可能当主查询中
的列值改变之后,子查询必须重新查询一次。查询嵌套层次越多,效率越低,因此
应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉尽可能多的
行。

5.避免困难的正规表达式
MATCHES和LIKE关键字支持通配符匹配,技术上叫正规表达式。但这种匹配特别耗
费时间。例如:SELECT * FROM customer WHERE zipcode LIKE “98_ _ _”
即使在zipcode字段上建立了索引,在这种情况下也还是采用顺序扫描的方式。如
果把语句改为SELECT * FROM customer WHERE zipcode >“98000”,在执行查询
时就会利用索引来查询,显然会大大提高速度。
另外,还要避免非开始的子串。例如语句:SELECT * FROM customer WHERE
zipcode[2,3] >“80”,在where子句中采用了非开始子串,因而这个语句也不会
使用索引。

6.使用临时表加速查询,SQL2000中还可以使用表变量来代替临时表
把表的一个子集进行排序并创建临时表,有时能加速查询。它有助于避免多重排序
操作,而且在其他方面还能简化优化器的工作。例如:
SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
AND cust.postcode>“98000”
ORDER BY cust.name
如果这个查询要被执行多次而不止一次,可以把所有未付款的客户找出来放在一个
临时文件中,并按客户的名字进行排序:
SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
ORDER BY cust.name
INTO TEMP cust_with_balance
然后以下面的方式在临时表中查询:
SELECT * FROM cust_with_balance
WHERE postcode>“98000”
临时表中的行要比主表中的行少,而且物理顺序就是所要求的顺序,减少了磁盘
I/O,所以查询工作量可以得到大幅减少。
注意:临时表创建后不会反映主表的修改。在主表中数据频繁修改的情况下,注意
不要丢失数据。

7.用排序来取代非顺序存取
非顺序磁盘存取是最慢的操作,表现在磁盘存取臂的来回移动。SQL语句隐藏了这
一情况,使得我们在写应用程序时很容易写出要求存取大量非顺序页的查询。
有些时候,用数据库的排序能力来替代非顺序的存取能改进查询。





zjcxc 元老 2003-11-01
  • 打赏
  • 举报
回复
给你看两篇优化的,你可以知道合理的索引和数据处理方法的重要性




如何让你的SQL运行得更快
---- 人们在使用SQL时往往会陷入一个误区,即太关注于所得的结果是否正确,而忽略
了不同的实现方法之间可能存在的性能差异,这种性能差异在大型的或是复杂的数据库
环境中(如联机事务处理OLTP或决策支持系统DSS)中表现得尤为明显。笔者在工作实践
中发现,不良的SQL往往来自于不恰当的索引设计、不充份的连接条件和不可优化的whe
re子句。在对它们进行适当的优化后,其运行速度有了明显地提高!下面我将从这三个
方面分别进行总结:
---- 为了更直观地说明问题,所有实例中的SQL运行时间均经过测试,不超过1秒的均
表示为(< 1秒)。
---- 测试环境--
---- 主机:HP LH II
---- 主频:330MHZ
---- 内存:128兆
---- 操作系统:Operserver5.0.4
----数据库:Sybase11.0.3
一、不合理的索引设计
----例:表record有620000行,试看在不同的索引下,下面几个 SQL的运行情况:
---- 1.在date上建有一非个群集索引
select count(*) from record where date >
'19991201' and date < '19991214'and amount >
2000 (25秒)
select date,sum(amount) from record group by date
(55秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH') (27秒)
---- 分析:
----date上有大量的重复值,在非群集索引下,数据在物理上随机存放在数据页上,在
范围查找时,必须执行一次表扫描才能找到这一范围内的全部行。
---- 2.在date上的一个群集索引
select count(*) from record where date >
'19991201' and date < '19991214' and amount >
2000 (14秒)
select date,sum(amount) from record group by date
(28秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH')(14秒)
---- 分析:
---- 在群集索引下,数据在物理上按顺序在数据页上,重复值也排列在一起,因而在范
围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范
围扫描,提高了查询速度。
---- 3.在place,date,amount上的组合索引
select count(*) from record where date >
'19991201' and date < '19991214' and amount >
2000 (26秒)
select date,sum(amount) from record group by date
(27秒)
select count(*) from record where date >
'19990901' and place in ('BJ', 'SH')(< 1秒)
---- 分析:
---- 这是一个不很合理的组合索引,因为它的前导列是place,第一和第二条SQL没有引
用place,因此也没有利用上索引;第三个SQL使用了place,且引用的所有列都包含在组
合索引中,形成了索引覆盖,所以它的速度是非常快的。
---- 4.在date,place,amount上的组合索引
select count(*) from record where date >
'19991201' and date < '19991214' and amount >
2000(< 1秒)
select date,sum(amount) from record group by date
(11秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH')(< 1秒)
---- 分析:
---- 这是一个合理的组合索引。它将date作为前导列,使每个SQL都可以利用索引,并
且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优。
---- 5.总结:
---- 缺省情况下建立的索引是非群集索引,但有时它并不是最佳的;合理的索引设计要
建立在对各种查询的分析和预测上。一般来说:
---- ①.有大量重复值、且经常有范围查询
(between, >,< ,>=,< =)和order by
、group by发生的列,可考虑建立群集索引;
---- ②.经常同时存取多列,且每列都含有重复值可考虑建立组合索引;
---- ③.组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列。

二、不充份的连接条件:
---- 例:表card有7896行,在card_no上有一个非聚集索引,表account有191122行,在
account_no上有一个非聚集索引,试看在不同的表连接条件下,两个SQL的执行情况:

select sum(a.amount) from account a,
card b where a.card_no = b.card_no(20秒)
---- 将SQL改为:
select sum(a.amount) from account a,
card b where a.card_no = b.card_no and a.
account_no=b.account_no(< 1秒)
---- 分析:
---- 在第一个连接条件下,最佳查询方案是将account作外层表,card作内层表,利用
card上的索引,其I/O次数可由以下公式估算为:
---- 外层表account上的22541页+(外层表account的191122行*内层表card上对应外层
表第一行所要查找的3页)=595907次I/O
---- 在第二个连接条件下,最佳查询方案是将card作外层表,account作内层表,利用
account上的索引,其I/O次数可由以下公式估算为:
---- 外层表card上的1944页+(外层表card的7896行*内层表account上对应外层表每一
行所要查找的4页)= 33528次I/O
---- 可见,只有充份的连接条件,真正的最佳方案才会被执行。
---- 总结:
---- 1.多表操作在被实际执行前,查询优化器会根据连接条件,列出几组可能的连接方
案并从中找出系统开销最小的最佳方案。连接条件要充份考虑带有索引的表、行数多的
表;内外表的选择可由公式:外层表中的匹配行数*内层表中每一次查找的次数确定,乘
积最小为最佳方案。
---- 2.查看执行方案的方法-- 用set showplanon,打开showplan选项,就可以看到连
接顺序、使用何种索引的信息;想看更详细的信息,需用sa角色执行dbcc(3604,310,30
2)。
三、不可优化的where子句
---- 1.例:下列SQL条件语句中的列都建有恰当的索引,但执行速度却非常慢:
select * from record where
substring(card_no,1,4)='5378'(13秒)
select * from record where
amount/30< 1000(11秒)
select * from record where
convert(char(10),date,112)='19991201'(10秒)
---- 分析:
---- where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不
进行表搜索,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么
就可以被SQL优化器优化,使用索引,避免表搜索,因此将SQL重写成下面这样:
select * from record where card_no like
'5378%'(< 1秒)
select * from record where amount
< 1000*30(< 1秒)
select * from record where date= '1999/12/01'
(< 1秒)
---- 你会发现SQL明显快起来!
---- 2.例:表stuff有200000行,id_no上有非群集索引,请看下面这个SQL:
select count(*) from stuff where id_no in('0','1')
(23秒)
---- 分析:
---- where条件中的'in'在逻辑上相当于'or',所以语法分析器会将in ('0','1')转化
为id_no ='0' or id_no='1'来执行。我们期望它会根据每个or子句分别查找,再将结果
相加,这样可以利用id_no上的索引;但实际上(根据showplan),它却采用了"OR策略"
,即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉
重复行,最后从这个临时表中计算结果。因此,实际过程没有利用id_no上索引,并且完
成时间还要受tempdb数据库性能的影响。
---- 实践证明,表的行数越多,工作表的性能就越差,当stuff有620000行时,执行时
间竟达到220秒!还不如将or子句分开:
select count(*) from stuff where id_no='0'
select count(*) from stuff where id_no='1'
---- 得到两个结果,再作一次加法合算。因为每句都使用了索引,执行时间只有3秒,
在620000行下,时间也只有4秒。或者,用更好的方法,写一个简单的存储过程:
create proc count_stuff as
declare @a int
declare @b int
declare @c int
declare @d char(10)
begin
select @a=count(*) from stuff where id_no='0'
select @b=count(*) from stuff where id_no='1'
end
select @c=@a+@b
select @d=convert(char(10),@c)
print @d
---- 直接算出结果,执行时间同上面一样快!
---- 总结:
---- 可见,所谓优化即where子句利用了索引,不可优化即发生了表扫描或额外开销。

---- 1.任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时
要尽可能将操作移至等号右边。
---- 2.in、or子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把
子句拆开;拆开的子句中应该包含索引。
---- 3.要善于使用存储过程,它使SQL变得更加灵活和高效。
---- 从以上这些例子可以看出,SQL优化的实质就是在结果正确的前提下,用优化器可
以识别的语句,充份利用索引,减少表扫描的I/O次数,尽量避免表搜索的发生。其实S
QL的性能优化是一个复杂的过程,上述这些只是在应用层次的一种体现,深入研究还会
涉及数据库层的资源配置、网络层的流量控制以及操作系统层的总体设计。
txlicenhe 2003-11-01
  • 打赏
  • 举报
回复
可以考虑这样

城市 区号 数据始   数据止
长春 431 431 431
长春 431 4315 4319
...
zjcxc 元老 2003-11-01
  • 打赏
  • 举报
回复
你看看SQL自身联机帮助上的说明:


使用聚集索引
聚集索引确定表中数据的物理顺序。聚集索引类似于电话簿,后者按姓氏排列数据。由于聚集索引规定数据在表中的物理存储顺序,因此一个表只能包含一个聚集索引。但该索引可以包含多个列(组合索引),就像电话簿按姓氏和名字进行组织一样。

聚集索引对于那些经常要搜索范围值的列特别有效。使用聚集索引找到包含第一个值的行后,便可以确保包含后续索引值的行在物理相邻。例如,如果应用程序执行的一个查询经常检索某一日期范围内的记录,则使用聚集索引可以迅速找到包含开始日期的行,然后检索表中所有相邻的行,直到到达结束日期。这样有助于提高此类查询的性能。同样,如果对从表中检索的数据进行排序时经常要用到某一列,则可以将该表在该列上聚集(物理排序),避免每次查询该列时都进行排序,从而节省成本。

当索引值唯一时,使用聚集索引查找特定的行也很有效率。例如,使用唯一雇员 ID 列 emp_id 查找特定雇员的最快速的方法,是在 emp_id 列上创建聚集索引或 PRIMARY KEY 约束。



说明 如果该表上尚未创建聚集索引,且在创建 PRIMARY KEY 约束时未指定非聚集索引,PRIMARY KEY 约束会自动创建聚集索引。


也可以在 lname(姓氏)列和 fname(名字)列上创建聚集索引,因为雇员记录常常是按姓名而不是按雇员 ID 分组和查询的。

注意事项
定义聚集索引键时使用的列越少越好,这一点很重要。如果定义了一个大型的聚集索引键,则同一个表上定义的任何非聚集索引都将增大许多,因为非聚集索引条目包含聚集键。当把 SQL 脚本保存到可用空间不足的磁盘上时,索引优化向导不返回错误。有关 Microsoft® SQL Server™ 2000 中如何实现非聚集索引的更多信息,请参见非聚集索引。

在分析过程中,索引优化向导会消耗相当多的 CPU 及内存资源。最好在生产服务器的测试版上执行优化,而不要在生产服务器上执行。此外,最好在另一台计算机上而非运行 SQL Server 的计算机上运行该向导。该向导不能用于在 SQL Server 6.5 版或更早版本的数据库中选择或创建索引及统计信息。

在创建聚集索引之前,应先了解您的数据是如何被访问的。可考虑将聚集索引用于:

包含大量非重复值的列。


使用下列运算符返回一个范围值的查询:BETWEEN、>、>=、< 和 <=。


被连续访问的列。


返回大型结果集的查询。


经常被使用联接或 GROUP BY 子句的查询访问的列;一般来说,这些是外键列。对 ORDER BY 或 GROUP BY 子句中指定的列进行索引,可以使 SQL Server 不必对数据进行排序,因为这些行已经排序。这样可以提高查询性能。


OLTP 类型的应用程序,这些程序要求进行非常快速的单行查找(一般通过主键)。应在主键上创建聚集索引。
聚集索引不适用于:

频繁更改的列
这将导致整行移动(因为 SQL Server 必须按物理顺序保留行中的数据值)。这一点要特别注意,因为在大数据量事务处理系统中数据是易失的。

宽键
来自聚集索引的键值由所有非聚集索引作为查找键使用,因此存储在每个非聚集索引的叶条目内。
zjcxc 元老 2003-11-01
  • 打赏
  • 举报
回复
几万的数据量,对SQL来说,是完全可以胜任的.
zjcxc 元老 2003-11-01
  • 打赏
  • 举报
回复
当然是第一种啦
你在要查找的数据库建立聚集索引.这样定位的速度就很快.只是在进行数据修改时速度会有一点影响.

而第二种方法,每次都要通过一个过程去解析,即没办法利用索引,又要对每个数据都解析一次,才能找到正确的记录,速度肯定慢.

34,874

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server相关内容讨论专区
社区管理员
  • 基础类社区
  • 二月十六
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧