搜尋

SQL查询优化 很多人不知道SQL语句在SQL SERVER中是如何执行的,他们担心自己所写的SQL语句会被SQL SERVER误解。比如: select * from table1 where and tID 10000 和执行: select * from table1 where tID 10000 and 一些人不知道以上两条语句的执行效率是否

SQL查询优化

很多人不知道SQL语句在SQL SERVER中是如何执行的,他们担心自己所写的SQL语句会被SQL SERVER误解。比如:  

select * from table1 where and tID > 10000  

和执行:  

select * from table1 where tID > 10000 and  

一些人不知道以上两条语句的执行效率是否一样,因为如果简单的从语句先后上看,这两个语句的确是不一样,如果tID是一个聚合索引,那么后一句仅仅从表的10000条以后的记录中查找就行了;而前一句则要先从全表中查找看有几个name='zhangsan'的,而后再根据限制条件条件tID>10000来提出查询结果。  

事实上,这样的担心是不必要的。SQL SERVER中有一个“查询分析优化器”,它可以计算出where子句中的搜索条件并确定哪个索引能缩小表扫描的搜索空间,也就是说,它能实现自动优化。  

虽然查询优化器可以根据where子句自动的进行查询优化,但大家仍然有必要了解一下“查询优化器”的工作原理,如非这样,有时查询优化器就会不按照您的本意进行快速查询。  

在查询分析阶段,查询优化器查看查询的每个阶段并决定限制需要扫描的数据量是否有用。如果一个阶段可以被用作一个扫描参数(SARG),那么就称之为可优化的,并且可以利用索引快速获得所需数据。  

SARG的定义:用于限制搜索的一个操作,因为它通常是指一个特定的匹配,一个值得范围内的匹配或者两个以上条件的AND连接。形式如下:  

列名 操作符   

或  

操作符列名  

列名可以出现在操作符的一边,而常数或变量出现在操作符的另一边。如:  

Name=’张三’  

价格>5000  

5000

Name=’张三’ and 价格>5000  

如果一个表达式不能满足SARG的形式,那它就无法限制搜索的范围了,也就是SQL SERVER必须对每一行都判断它是否满足WHERE子句中的所有条件。所以一个索引对于不满足SARG形式的表达式来说是无用的。  

介绍完SARG后,我们来总结一下使用SARG以及在实践中遇到的和某些资料上结论不同的经验:  

1、Like语句是否属于SARG取决于所使用的通配符的类型 

如:name like ‘张%’ ,这就属于SARG  

而:name like ‘%张’ ,就不属于SARG。  

原因是通配符%在字符串的开通使得索引无法使用。  

2、or 会引起全表扫描 

Name=’张三’ and 价格>5000 符号SARG,而:Name=’张三’ or 价格>5000 则不符合SARG。使用or会引起全表扫描。  

3、非操作符、函数引起的不满足SARG形式的语句 

不满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、、!、NOT EXISTS、NOT IN、NOT LIKE等,另外还有函数。下面就是几个不满足SARG形式的例子:  

ABS(价格)

Name like ‘%三’  

有些表达式,如:  

WHERE 价格*2>5000  

SQL SERVER也会认为是SARG,SQL SERVER会将此式转化为:  

WHERE 价格>2500/2  

但我们不推荐这样使用,因为有时SQL SERVER不能保证这种转化与原始表达式是完全等价的。  

4、IN 的作用相当与OR 

语句:  

Select * from table1 where tid in (2,3)  

和  

Select * from table1 where tid=2 or tid=3  

是一样的,都会引起全表扫描,如果tid上有索引,其索引也会失效。  

5、尽量少用NOT 

6、exists 和 in 的执行效率是一样的 

很多资料上都显示说,exists要比in的执行效率要高,同时应尽可能的用not exists来代替not in。但事实上,我试验了一下,发现二者无论是前面带不带not,香港虚拟主机,二者之间的执行效率都是一样的。因为涉及子查询,我们试验这次用SQL SERVER自带的pubs数据库。运行前我们可以把SQL SERVER的statistics I/O状态打开。  

(1)select title,price from titles where title_id in (select title_id from sales where qty>30)  

该句的执行结果为:  

表 'sales'。扫描计数 18,逻辑读 56 次,物理读 0 次,预读 0 次。  

表 'titles'。扫描计数 1,逻辑读 2 次,物理读 0 次,预读 0 次。  

(2)select title,price from titles where exists (select * from sales where sales.title_id=titles.title_id and qty>30)  

第二句的执行结果为:  

表 'sales'。扫描计数 18,逻辑读 56 次,物理读 0 次,预读 0 次。  

表 'titles'。扫描计数 1,逻辑读 2 次,物理读 0 次,预读 0 次。  

我们从此可以看到用exists和用in的执行效率是一样的。  

7、用函数charindex()和前面加通配符%的LIKE执行效率一样 

前面,我们谈到,如果在LIKE前面加上通配符%,那么将会引起全表扫描,美国服务器,所以其执行效率是低下的。但有的资料介绍说,用函数charindex()来代替LIKE速度会有大的提升,经我试验,发现这种说明也是错误的:  

select gid,title,fariqi,reader from tgongwen where charindex('刑侦支队',reader)>0 and fariqi>'2004-5-5'  

用时:7秒,另外:扫描计数 4,逻辑读 7155 次,物理读 0 次,预读 0 次。  

select gid,title,fariqi,reader from tgongwen where reader like '%' + '刑侦支队' + '%' and fariqi>'2004-5-5'  

用时:7秒,另外:扫描计数 4,逻辑读 7155 次,物理读 0 次,预读 0 次。  

8、union并不绝对比or的执行效率高 

我们前面已经谈到了在where子句中使用or会引起全表扫描,一般的,我所见过的资料都是推荐这里用union来代替or。事实证明,这种说法对于大部分都是适用的。  

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' or gid>9990000  

用时:68秒。扫描计数 1,逻辑读 404008 次,物理读 283 次,预读 392163 次。  

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'  

union  

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid>9990000  

用时:9秒。扫描计数 8,逻辑读 67489 次,物理读 216 次,预读 7499 次。  

看来,用union在通常情况下比用or的效率要高的多。  

但经过试验,笔者发现如果or两边的查询列是一样的话,那么用union则反倒和用or的执行速度差很多,虽然这里union扫描的是索引,而or扫描的是全表。  

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16' or fariqi='2004-2-5'  

用时:6423毫秒。扫描计数 2,逻辑读 14726 次,物理读 1 次,预读 7176 次。  

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'  

union  

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-2-5'  

用时:11640毫秒。扫描计数 8,逻辑读 14806 次,物理读 108 次,预读 1144 次。  

9、字段提取要按照“需多少、提多少”的原则,避免“select *” 

我们来做一个试验:  

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc  

用时:4673毫秒  

select top 10000 gid,fariqi,title from tgongwen order by gid desc  

用时:1376毫秒  

select top 10000 gid,fariqi from tgongwen order by gid desc  

用时:80毫秒  

由此看来,我们每少提取一个字段,数据的提取速度就会有相应的提升。提升的速度还要看您舍弃的字段的大小来判断。  

10、count(*)不比count(字段)慢 

某些资料上说:用*会统计所有列,显然要比一个世界的列名效率低。这种说法其实是没有根据的。我们来看:  

select count(*) from Tgongwen  

用时:1500毫秒  

select count(gid) from Tgongwen  

用时:1483毫秒  

select count(fariqi) from Tgongwen  

用时:3140毫秒  

select count(title) from Tgongwen  

用时:52050毫秒  

从以上可以看出,如果用count(*)和用count(主键)的速度是相当的,而count(*)却比其他任何除主键以外的字段汇总速度要快,而且字段越长,汇总的速度就越慢。我想,如果用count(*), SQL SERVER可能会自动查找最小字段来汇总的。当然,如果您直接写count(主键)将会来的更直接些。  

11、order by按聚集索引列排序效率最高 

我们来看:(gid是主键,fariqi是聚合索引列)  

select top 10000 gid,fariqi,reader,title from tgongwen  

用时:196 毫秒。 扫描计数 1,逻辑读 289 次,物理读 1 次,预读 1527 次。  

select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc  

用时:4720毫秒。 扫描计数 1,逻辑读 41956 次,物理读 0 次,预读 1287 次。  

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc  

用时:4736毫秒。 扫描计数 1,逻辑读 55350 次,物理读 10 次,预读 775 次。  

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc  

用时:173毫秒。 扫描计数 1,逻辑读 290 次,物理读 0 次,预读 0 次。  

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc  

用时:156毫秒。 扫描计数 1,逻辑读 289 次,物理读 0 次,虚拟主机,预读 0 次。  

从以上我们可以看出,不排序的速度以及逻辑读次数都是和“order by 聚集索引列” 的速度是相当的,但这些都比“order by 非聚集索引列”的查询速度是快得多的。  

同时,按照某个字段进行排序的时候,无论是正序还是倒序,速度是基本相当的。  

12、高效的TOP 

事实上,在查询和提取超大容量的数据集时,影响数据库响应时间的最大因素不是数据查找,而是物理的I/0操作。如:  

select top 10 * from (  

select top 10000 gid,fariqi,title from tgongwen  

where neibuyonghu='办公室'  

order by gid desc) as a  

order by gid asc  

这条语句,从理论上讲,整条语句的执行时间应该比子句的执行时间长,但事实相反。因为,子句执行后返回的是10000条记录,而整条语句仅返回10条语句,所以影响数据库响应时间最大的因素是物理I/O操作。而限制物理I/O操作此处的最有效方法之一就是使用TOP关键词了。TOP关键词是SQL SERVER中经过系统优化过的一个用来提取前几条或前几个百分比数据的词。经笔者在实践中的应用,发现TOP确实很好用,效率也很高。但这个词在另外一个大型数据库ORACLE中却没有,这不能说不是一个遗憾,虽然在ORACLE中可以用其他方法(如:rownumber)来解决。在以后的关于“实现千万级数据的分页显示存储过程”的讨论中,我们就将用到TOP这个关键词。  

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
MySQL的許可與其他數據庫系統相比如何?MySQL的許可與其他數據庫系統相比如何?Apr 25, 2025 am 12:26 AM

MySQL使用的是GPL許可證。 1)GPL許可證允許自由使用、修改和分發MySQL,但修改後的分發需遵循GPL。 2)商業許可證可避免公開修改,適合需要保密的商業應用。

您什麼時候選擇InnoDB而不是Myisam,反之亦然?您什麼時候選擇InnoDB而不是Myisam,反之亦然?Apr 25, 2025 am 12:22 AM

選擇InnoDB而不是MyISAM的情況包括:1)需要事務支持,2)高並發環境,3)需要高數據一致性;反之,選擇MyISAM的情況包括:1)主要是讀操作,2)不需要事務支持。 InnoDB適合需要高數據一致性和事務處理的應用,如電商平台,而MyISAM適合讀密集型且無需事務的應用,如博客系統。

在MySQL中解釋外鍵的目的。在MySQL中解釋外鍵的目的。Apr 25, 2025 am 12:17 AM

在MySQL中,外鍵的作用是建立表與表之間的關係,確保數據的一致性和完整性。外鍵通過引用完整性檢查和級聯操作維護數據的有效性,使用時需注意性能優化和避免常見錯誤。

MySQL中有哪些不同類型的索引?MySQL中有哪些不同類型的索引?Apr 25, 2025 am 12:12 AM

MySQL中有四種主要的索引類型:B-Tree索引、哈希索引、全文索引和空間索引。 1.B-Tree索引適用於範圍查詢、排序和分組,適合在employees表的name列上創建。 2.哈希索引適用於等值查詢,適合在MEMORY存儲引擎的hash_table表的id列上創建。 3.全文索引用於文本搜索,適合在articles表的content列上創建。 4.空間索引用於地理空間查詢,適合在locations表的geom列上創建。

您如何在MySQL中創建索引?您如何在MySQL中創建索引?Apr 25, 2025 am 12:06 AM

toCreateAnIndexinMysql,usethecReateIndexStatement.1)forasingLecolumn,使用“ createIndexIdx_lastNameEnemployees(lastName); 2)foracompositeIndex,使用“ createIndexIndexIndexIndexIndexDx_nameOmplayees(lastName,firstName,firstName);” 3)forauniqe instex,creationexexexexex,

MySQL與Sqlite有何不同?MySQL與Sqlite有何不同?Apr 24, 2025 am 12:12 AM

MySQL和SQLite的主要區別在於設計理念和使用場景:1.MySQL適用於大型應用和企業級解決方案,支持高性能和高並發;2.SQLite適合移動應用和桌面軟件,輕量級且易於嵌入。

MySQL中的索引是什麼?它們如何提高性能?MySQL中的索引是什麼?它們如何提高性能?Apr 24, 2025 am 12:09 AM

MySQL中的索引是數據庫表中一列或多列的有序結構,用於加速數據檢索。 1)索引通過減少掃描數據量提升查詢速度。 2)B-Tree索引利用平衡樹結構,適合範圍查詢和排序。 3)創建索引使用CREATEINDEX語句,如CREATEINDEXidx_customer_idONorders(customer_id)。 4)複合索引可優化多列查詢,如CREATEINDEXidx_customer_orderONorders(customer_id,order_date)。 5)使用EXPLAIN分析查詢計劃,避

說明如何使用MySQL中的交易來確保數據一致性。說明如何使用MySQL中的交易來確保數據一致性。Apr 24, 2025 am 12:09 AM

在MySQL中使用事務可以確保數據一致性。 1)通過STARTTRANSACTION開始事務,執行SQL操作後用COMMIT提交或ROLLBACK回滾。 2)使用SAVEPOINT可以設置保存點,允許部分回滾。 3)性能優化建議包括縮短事務時間、避免大規模查詢和合理使用隔離級別。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中