(1) 有些书籍会提到,使用「LIKE、%」做模糊查询时,即使您已替某个字段建立索引 (如下方代码的 CustomerID
字段),但以常量字符开头才会使用到索引,若以万用字符 (%) 开头则不会使用索引,如下所示:
SELECT * FROM Orders WHERE CustomerID LIKE 'D%'; --使用索引
SELECT * FROM Orders WHERE CustomerID LIKE '%D'; --不使用索引
但经反复测试,这种语法是否会使用到索引,抑或会逐笔扫描,并非绝对的。仍要看所下的查询关键词,以及字段内 所存储的数据内容而定。但对于存储数据笔数庞大的数据表,最好还是少用 LIKE 做模糊查询。
SELECT * FROM Orders WHERE DATEPART(yyyy, OrderDate) = 1996 AND DATEPART(mm, OrderDate)=7
可改成
SELECT * FROM Orders WHERE OrderDate BETWEEN '19960701' AND '19960731'
SELECT * FROM Orders WHERE SUBSTRING(CustomerID, 1, 1) = 'D'
可改成
SELECT * FROM Orders WHERE CustomerID LIKE 'D%'
注意当您在下 UPDATE、DELETE 语句时,若有采用 WHERE 子句,也应符合上述原则。
5、AND 与 OR 的使用
在 AND 运算中,「只要有一个」条件有用到索引 (如下方的 CustomerID),即可大幅提升查询速度,如下所示:
SELECT * FROM Orders WHERE CustomerID='VINET' AND Freight=32.3800 --使用索引
SELECT * FROM Orders WHERE Freight=32.3800 --不使用索引
但在 OR 运算中,则要「所有的」条件都有可用的索引,才能使用索引来提升查询速度。因此 OR 运算符的使用必须特别小心。
若您将上方 AND 的范例,逻辑运算符改成 OR 的话,如下所示:
SELECT * FROM Orders WHERE CustomerID='VINET' OR Freight=32.3800
在使用 OR 运算符时,只要有一个条件 (字段) 没有可用的索引,则其它所有的条件 (字段) 都有索引也没用,如上sql,把整个数据表或整个集簇索引都扫描过,以逐笔比对是否有符合条件的数据。
据网络上文件的说法,上述的 OR 运算语句,我们还可用 UNION 联集适当地改善,如下:
SELECT * FROM Orders WHERE CustomerID='VINET'
UNION
SELECT * FROM Orders WHERE Freight=32.3800
会发现上半段的查询会使用索引,但下半段仍用集簇索引扫描,对性能不无小补。
SET STATISTICS TIME ON
SELECT OrderID, ROW_NUMBER() OVER(ORDER BY OrderID) AS 编号
FROM dbo.Orders
但如果是传统的「子查询」写法,或 辅以 AS 关键词的「衍生数据表」的语法,写法必须如下
SET STATISTICS TIME ON
SELECT OrderID,
(SELECT COUNT(*) FROM dbo.Orders AS 内圈
WHERE 内圈.OrderID <= 外圈.OrderID) AS 编号
FROM dbo.Orders AS 外圈
ORDER BY 编号
-- 用 ROW_NUMBER 的写法,改查询 AdventureWorks 数据库 (31,465 笔数据,要 677 ms,还不到 1 秒钟)
SELECT SalesOrderID, ROW_NUMBER() OVER(ORDER BY SalesOrderID) AS rownum
FROM Sales.SalesOrderHeader
-- 用「子查询」的写法,改查询 AdventureWorks 数据库 (31,465 笔数据,要 233,835 ms,将近 4 分钟)
SELECT SalesOrderID,
(SELECT COUNT(*) FROM Sales.SalesOrderHeader AS 内圈
WHERE 内圈.SalesOrderID <= 外圈.SalesOrderID) AS 编号
FROM Sales.SalesOrderHeader AS 外圈
ORDER BY 编号