SQL循环插⼊批量数据
declare @i int
declare @qid int
set @i=1
set @qid=100
while @i<50000
begin
insert into Order(orderid,ordername) values(@qid,'订单名称')
set @i=@i+1
set @qid=@qid+1
end
海量语句查询代码优化:
具体要注意的:
1.应尽量避免在 where ⼦句中对字段进⾏ null 值判断,否则将导致引擎放弃使⽤索引⽽进⾏全表扫描,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
2.应尽量避免在 where ⼦句中使⽤!=或<>操作符,否则将引擎放弃使⽤索引⽽进⾏全表扫描。优化器将⽆法通过索引来确定将要命中的⾏数,因此需要搜索该表的所有⾏。
3.应尽量避免在 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
4.in 和 not in 也要慎⽤,因为IN会使系统⽆法使⽤索引,⽽只能直接搜索表中的数据。如:
select id from t where num in(1,2,3)
对于连续的数值,能⽤ between 就不要⽤ in 了:
select id from t where num between 1 and 3
5.尽量避免在索引过的字符数据中,使⽤⾮打头字母搜索。这也使得引擎⽆法利⽤索引。
见如下例⼦:
SELECT * FROM T1 WHERE NAME LIKE ‘%L%’
SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’
SELECT * FROM T1 WHERE NAME LIKE ‘L%’
即使NAME字段建有索引,前两个查询依然⽆法利⽤索引完成加快操作,引擎不得不对全表所有数据逐条操作来完成任务。⽽第三个查询能够使⽤索引来加快操作。
6.必要时强制查询优化器使⽤某个索引,如在 where ⼦句中使⽤参数,也会导致全表扫描。因为SQL只有在运⾏时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运⾏时;它必须在编译时进⾏选择。然 ⽽,如果在编译时建⽴访问计划,变量的值还是未知的,因⽽⽆法作为索引选择的输⼊项。如下⾯语句将进⾏全表扫描:
select id from t where
可以改为强制查询使⽤索引:
select id from t with(index(索引名)) where
7.应尽量避免在 where ⼦句中对字段进⾏表达式操作,这将导致引擎放弃使⽤索引⽽进⾏全表扫描。如:
SELECT * FROM T1 WHERE F1/2=100
应改为:
SELECT * FROM T1 WHERE F1=100*2
SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=’5378’
应改为:
SELECT * FROM RECORD WHERE CARD_NO LIKE ‘5378%’
SELECT member_number, first_name, last_name FROM members
WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21
应改为:
SELECT member_number, first_name, last_name FROM members
WHERE dateofbirth < DATEADD(yy,-21,GETDATE())
即:任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移⾄等号右边。
8.应尽量避免在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'
9.不要在 where ⼦句中的“=”左边进⾏函数、算术运算或其他表达式运算,否则系统将可能⽆法正确使⽤索引。
10.在使⽤索引字段作为条件时,如果该索引是复合索引,那么必须使⽤到该索引中的第⼀个字段作为条件时才能保证系统使⽤该索引,否则该索引将不会被使⽤,并且应尽可能的让字段顺序与索引顺序相⼀致。
11.很多时候⽤ exists是⼀个好的选择:
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)
SELECT SUM(T1.C1)FROM T1 WHERE(
(SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0)
SELECT SUM(T1.C1) FROM T1WHERE EXISTS(
SELECT * FROM T2 WHERE T2.C2=T1.C2)
两者产⽣相同的结果,但是后者的效率显然要⾼于前者。因为后者不会产⽣⼤量锁定的表扫描或是索引扫描。
如果你想校验表⾥是否存在某条纪录,不要⽤count(*)那样效率很低,⽽且浪费服务器资源。可以⽤EXISTS代替。如:
IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx')
可以写成:
IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')
经常需要写⼀个T_SQL语句⽐较⼀个⽗结果集和⼦结果集,从⽽到是否存在在⽗结果集中有⽽在⼦结果集中没有的记录,如:SELECT a.hdr_key FROM hdr_tbl a---- tbl a 表⽰tbl⽤别名a代替
WHERE NOT EXISTS (SELECT * FROM dtl_tbl b WHERE a.hdr_key = b.hdr_key)
SELECT a.hdr_key FROM hdr_tbl a
LEFT JOIN dtl_tbl b ON a.hdr_key = b.hdr_key WHERE b.hdr_key IS NULL
SELECT hdr_key FROM hdr_tbl
WHERE hdr_key NOT IN (SELECT hdr_key FROM dtl_tbl)
三种写法都可以得到同样正确的结果,但是效率依次降低。
12.尽量使⽤表变量来代替临时表。如果表变量包含⼤量数据,请注意索引⾮常有限(只有主键索引)。
13.避免频繁创建和删除临时表,以减少系统表资源的消耗。
14.临时表并不是不可使⽤,适当地使⽤它们可以使某些例程更有效,例如,当需要重复引⽤⼤型表或常⽤表中的某个数据集时。但是,对于⼀次性事件,最好使⽤导出表。
15.在新建临时表时,如果⼀次性插⼊数据量很⼤,那么可以使⽤ select into 代替 create table,避免造成⼤量 log ,以提⾼速度;如果数据量不⼤,为了缓和系统表的资源,应先create table,然后insert。
16.如果使⽤到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
17.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。⽆需在执⾏存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
18.尽量避免⼤事务操作,提⾼系统并发能⼒。
19.尽量避免向客户端返回⼤数据量,若数据量过⼤,应该考虑相应需求是否合理。
20. 避免使⽤不兼容的数据类型。例如float和int、char和varchar、binary和varbinary是不兼容的。数据类型的不兼容可能使优化器⽆法执⾏⼀些本来可以进⾏的优化操作。例如:
SELECT name FROM employee WHERE salary > 60000
在这条语句中,如salary字段是money型的,则优化器很难对其进⾏优化,因为60000是个整型数。我们应当在编程时将整型转化成为钱币型,⽽不要等到运⾏时转化。
21.充分利⽤连接条件,在某种情况下,两个表之间可能不只⼀个的连接条件,这时在 WHERE ⼦句中将连接条件完整的写上,有可能⼤⼤提⾼查询速度。
例:
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO
SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO AND
A.ACCOUNT_NO=
B.ACCOUNT_NO
第⼆句将⽐第⼀句执⾏快得多。
22、使⽤视图加速查询
把表的⼀个⼦集进⾏排序并创建视图,有时能加速查询。它有助于避免多重排序 操作,⽽且在其他⽅⾯还能简化优化器的⼯作。例如:SELECT cust.name,rcvbles.balance,……other columns
FROM cust,rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
sql语句查询不包含AND rcvblls.balance>0
AND cust.postcode>“98000”
ORDER BY cust.name
如果这个查询要被执⾏多次⽽不⽌⼀次,可以把所有未付款的客户出来放在⼀个视图中,并按客户的名字进⾏排序:
CREATE VIEW DBO.V_CUST_RCVLBES
AS
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
然后以下⾯的⽅式在视图中查询:
SELECT * FROM V_CUST_RCVLBES
WHERE postcode>“98000”
视图中的⾏要⽐主表中的⾏少,⽽且物理顺序就是所要求的顺序,减少了磁盘I/O,所以查询⼯作量可以得到⼤幅减少。
23、能⽤DISTINCT的就不⽤GROUP BY
SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID
可改为:
SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10
24.能⽤UNION ALL就不要⽤UNION
UNION ALL不执⾏SELECT DISTINCT函数,这样就会减少很多不必要的资源
25.尽量不要⽤SELECT INTO语句。
SELECT INOT 语句会导致表锁定,阻⽌其他⽤户访问该表。
上⾯我们提到的是⼀些基本的提⾼查询速度的注意事项,但是在更多的情况下,往往需要反复试验⽐较不同的语句以得到最佳⽅案。最好的⽅法当然是测试,看实现 相同功能的SQL语句哪个执⾏时间最少,但是数据库中如果数据量很少,是⽐较不出来的,这时可以⽤查看执⾏计划,即:把实现相同功能的多条SQL语句考到 查询分析器,按CTRL+L看查所利⽤的索引,表扫描次数(这两个对性能影响最⼤),总体上看询成本百分⽐即可。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。