前言
本文章引用自《SQL必知必会第5版》
书号:ISBN 978-7-115-53916-8
挑战题解决方案链接:Sams Teach Yourself SQL in 10 Minutes (Fifth Edition) Challenges – Ben Forta
本文章使用的数据库管理器是MySQL,本文章也提供了创建数据库的SQL脚本。
-- -----------------------------------------
-- Sams Teach Yourself SQL in 10 Minutes
-- http://forta.com/books/0672336073/
-- Example table creation scripts for MySQL.
-- -----------------------------------------
-- ----------------------
-- Create Customers table
-- ----------------------
CREATE TABLE Customers
(
cust_id char(10) NOT NULL ,
cust_name char(50) NOT NULL ,
cust_address char(50) NULL ,
cust_city char(50) NULL ,
cust_state char(5) NULL ,
cust_zip char(10) NULL ,
cust_country char(50) NULL ,
cust_contact char(50) NULL ,
cust_email char(255) NULL
);
-- -----------------------
-- Create OrderItems table
-- -----------------------
CREATE TABLE OrderItems
(
order_num int NOT NULL ,
order_item int NOT NULL ,
prod_id char(10) NOT NULL ,
quantity int NOT NULL ,
item_price decimal(8,2) NOT NULL
);
-- -------------------
-- Create Orders table
-- -------------------
CREATE TABLE Orders
(
order_num int NOT NULL ,
order_date datetime NOT NULL ,
cust_id char(10) NOT NULL
);
-- ---------------------
-- Create Products table
-- ---------------------
CREATE TABLE Products
(
prod_id char(10) NOT NULL ,
vend_id char(10) NOT NULL ,
prod_name char(255) NOT NULL ,
prod_price decimal(8,2) NOT NULL ,
prod_desc text NULL
);
-- --------------------
-- Create Vendors table
-- --------------------
CREATE TABLE Vendors
(
vend_id char(10) NOT NULL ,
vend_name char(50) NOT NULL ,
vend_address char(50) NULL ,
vend_city char(50) NULL ,
vend_state char(5) NULL ,
vend_zip char(10) NULL ,
vend_country char(50) NULL
);
-- -------------------
-- Define primary keys
-- -------------------
ALTER TABLE Customers ADD PRIMARY KEY (cust_id);
ALTER TABLE OrderItems ADD PRIMARY KEY (order_num, order_item);
ALTER TABLE Orders ADD PRIMARY KEY (order_num);
ALTER TABLE Products ADD PRIMARY KEY (prod_id);
ALTER TABLE Vendors ADD PRIMARY KEY (vend_id);
-- -------------------
-- Define foreign keys
-- -------------------
ALTER TABLE OrderItems ADD CONSTRAINT FK_OrderItems_Orders FOREIGN KEY (order_num) REFERENCES Orders (order_num);
ALTER TABLE OrderItems ADD CONSTRAINT FK_OrderItems_Products FOREIGN KEY (prod_id) REFERENCES Products (prod_id);
ALTER TABLE Orders ADD CONSTRAINT FK_Orders_Customers FOREIGN KEY (cust_id) REFERENCES Customers (cust_id);
ALTER TABLE Products ADD CONSTRAINT FK_Products_Vendors FOREIGN KEY (vend_id) REFERENCES Vendors (vend_id);
-- -------------------------------------------
-- Sams Teach Yourself SQL in 10 Minutes
-- http://forta.com/books/0672336073/
-- Example table population scripts for MySQL.
-- -------------------------------------------
-- ------------------------
-- Populate Customers table
-- ------------------------
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES('1000000001', 'Village Toys', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'John Smith', 'sales@villagetoys.com');
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
VALUES('1000000002', 'Kids Place', '333 South Lake Drive', 'Columbus', 'OH', '43333', 'USA', 'Michelle Green');
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES('1000000003', 'Fun4All', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'jjones@fun4all.com');
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email)
VALUES('1000000004', 'Fun4All', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Denise L. Stephens', 'dstephens@fun4all.com');
INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact)
VALUES('1000000005', 'The Toy Store', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'Kim Howard');
-- ----------------------
-- Populate Vendors table
-- ----------------------
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('BRS01','Bears R Us','123 Main Street','Bear Town','MI','44444', 'USA');
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('BRE02','Bear Emporium','500 Park Street','Anytown','OH','44333', 'USA');
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('DLL01','Doll House Inc.','555 High Street','Dollsville','CA','99999', 'USA');
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('FRB01','Furball Inc.','1000 5th Avenue','New York','NY','11111', 'USA');
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('FNG01','Fun and Games','42 Galaxy Road','London', NULL,'N16 6PS', 'England');
INSERT INTO Vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country)
VALUES('JTS01','Jouets et ours','1 Rue Amusement','Paris', NULL,'45678', 'France');
-- -----------------------
-- Populate Products table
-- -----------------------
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BR01', 'BRS01', '8 inch teddy bear', 5.99, '8 inch teddy bear, comes with cap and jacket');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BR02', 'BRS01', '12 inch teddy bear', 8.99, '12 inch teddy bear, comes with cap and jacket');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BR03', 'BRS01', '18 inch teddy bear', 11.99, '18 inch teddy bear, comes with cap and jacket');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BNBG01', 'DLL01', 'Fish bean bag toy', 3.49, 'Fish bean bag toy, complete with bean bag worms with which to feed it');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BNBG02', 'DLL01', 'Bird bean bag toy', 3.49, 'Bird bean bag toy, eggs are not included');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('BNBG03', 'DLL01', 'Rabbit bean bag toy', 3.49, 'Rabbit bean bag toy, comes with bean bag carrots');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('RGAN01', 'DLL01', 'Raggedy Ann', 4.99, '18 inch Raggedy Ann doll');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('RYL01', 'FNG01', 'King doll', 9.49, '12 inch king doll with royal garments and crown');
INSERT INTO Products(prod_id, vend_id, prod_name, prod_price, prod_desc)
VALUES('RYL02', 'FNG01', 'Queen doll', 9.49, '12 inch queen doll with royal garments and crown');
-- ---------------------
-- Populate Orders table
-- ---------------------
INSERT INTO Orders(order_num, order_date, cust_id)
VALUES(20005, '2012-05-01', '1000000001');
INSERT INTO Orders(order_num, order_date, cust_id)
VALUES(20006, '2012-01-12', '1000000003');
INSERT INTO Orders(order_num, order_date, cust_id)
VALUES(20007, '2012-01-30', '1000000004');
INSERT INTO Orders(order_num, order_date, cust_id)
VALUES(20008, '2012-02-03', '1000000005');
INSERT INTO Orders(order_num, order_date, cust_id)
VALUES(20009, '2012-02-08', '1000000001');
-- -------------------------
-- Populate OrderItems table
-- -------------------------
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20005, 1, 'BR01', 100, 5.49);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20005, 2, 'BR03', 100, 10.99);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20006, 1, 'BR01', 20, 5.99);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20006, 2, 'BR02', 10, 8.99);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20006, 3, 'BR03', 10, 11.99);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20007, 1, 'BR03', 50, 11.49);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20007, 2, 'BNBG01', 100, 2.99);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20007, 3, 'BNBG02', 100, 2.99);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20007, 4, 'BNBG03', 100, 2.99);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20007, 5, 'RGAN01', 50, 4.49);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20008, 1, 'RGAN01', 5, 4.99);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20008, 2, 'BR03', 5, 11.99);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20008, 3, 'BNBG01', 10, 3.49);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20008, 4, 'BNBG02', 10, 3.49);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20008, 5, 'BNBG03', 10, 3.49);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20009, 1, 'BNBG01', 250, 2.49);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20009, 2, 'BNBG02', 250, 2.49);
INSERT INTO OrderItems(order_num, order_item, prod_id, quantity, item_price)
VALUES(20009, 3, 'BNBG03', 250, 2.49);
1.了解SQL
1.1数据库基础
1.1.1主键
唯一标识表中每行的列称为主键。
表中的任何列都可以成为主键,成为主键需满足下列条件:
- 任意两行都不具有重复的主键值
- 每一行都必须具有一个主键值
- 主键列中的值可以修改,但不允许修改或更新
- 主键值不能重用,即某行从表中删除后,它的主键不能赋给以后的新行
1.2SQL扩展
标准的SQL由ANSI标准委员会管理,从而称为ANSI SQL。所有主要的DBMS(数据库管理系统)即使有自己的扩展,也都支持ANSI SQL。各个实现有自己的名称,如ORACLE的PL/SQL、微软SQL SERVER用的Transact-SQL等。
1.3关系表
相同的数据出现多次决不是一件好事,这是关系数据库设计的基础。关系表的设计就是要把信息分解成多个表,一类数据一个表。各表通过某些共同的值互相关联。
关系数据可以有效地存储,方便地处理。因此,关系数据库的可伸缩性比非关系数据库要好。所谓可伸缩性即能够适应不断增加的工作量而不失败。设计良好的数据库或应用程序称为可伸缩性好。
2.检索数据
大部分SQL开发人员喜欢对SQL关键字使用大写,对列名和表名使用小写,这样代码更易于阅读和调试。
2.1检索不同的值(DISTINCT)
关键字:DISTINCT
DISTINCT关键字作用于所有的列,不仅仅是跟着其后的那一列。
表:emp
SELECT DISTINCT job FROM emp;
SELECT DISTINCT job,salary FROM emp;
2.2限制结果
适用场景:只想返回第一行或者一定数量的行。
#从第一行返回2行数据 SELECT user_name FROM emp LIMIT 2 OFFSET 0; #从第一行返回2行数据 SELECT user_name FROM emp LIMIT 0,2;
2.3使用注释
行内注释:
-- 行内注释。--之后要有一个空格
#行内注释。
多行注释:
/*第一行注释
第二行注释*/
3.排序检索数据(ORDER BY)
关系数据库设计理论认为:如果不明确规定排序顺序,则不应该假定检索出的数据的顺序有任何意义。
在指定一条ORDER BY 子句时,应该保证它是SELECT语句中最后一条子句。
3.1按列位置排序
ORDER BY支持按相对列位置进行排序。缺点则是:不明确给出列名容易导致用错列名排序,其次在对SELECT清单改动时,容易忽略ORDER BY的改动,最后,不在SELECT清单中的排序列不能使用该技术。
#先按salary再按entry_date对数据排序(按相对列位置进行排序) SELECT salary,entry_date FROM emp ORDER BY 1,2; #先按salary再按entry_date对数据排序 SELECT salary,entry_date FROM emp ORDER BY salary,entry_date;
4.数据过滤
求值顺序 :where子句中可以包含任意数目的AND和OR操作符。但OR和AND组合时会带来求值顺序的问题。
#筛选工资4000以上的销售人员与管理人员 SELECT salary,entry_date,job FROM emp WHERE job = 'SALE' OR job='Manager' AND salary > 4000;
SQL语句在处理OR操作符前会优先处理AND操作符。因此上述SQL语句被解析为职位是销售+工资超过4000的管理。
解决方案:添加圆括号。
#筛选工资4000以上的销售人员与管理人员 SELECT salary,entry_date,job FROM emp WHERE (job = 'SALE' OR job='Manager') AND salary > 4000;
通配符过滤数据
通配符只能用于文本字段。
使用通配符的技巧:
- 不要过度使用通配符
- 在需要使用通配符的情况下,尽量不要把它们用在搜索模式的开始处。
5.创建计算字段
字段基本与列的定义相同,经常互换,不过数据库列一般称为列 ,而字段这个术语通常在计算字段这种场合下使用。
在SQL语句中可完成的许多转换和格式化工作都可以直接在客户端应用程序内完成。一般来说,在数据库服务器上完成这些操作比在客户端完成要快得多。
#筛选工资4000以上的销售人员与管理人员 SELECT salary,entry_date,job FROM emp WHERE (job = 'SALE' OR job='Manager') AND salary > 4000;
#筛选销售人员的个人简历 SELECT CONCAT(user_name,' resume=(',RTRIM(RESUME),')') FROM emp WHERE job = 'SALE';
#筛选销售人员的个人简历 SELECT CONCAT(user_name,' resume=(',RTRIM(RESUME),')') AS user_resume FROM emp WHERE job = 'SALE';
6.聚集函数
概念:对某些行运行的函数,计算并返回一个值。
- AVG()
- COUNT()
- MAX()
- MIN()
- SUM()
7.分组数据
7.1数据分组(GROUP BY)
#查找产品表中各个供应商提供的产品种类数
SELECT vend_id,COUNT(*) AS num_prods FROM products GROUP BY vend_id;
GROUP BY子句指示DBMS分组数据,然后对每个组而不是整个结果集进行聚集。
使用GROUP BY的一些规定:
- GROUP BY子句可以包含任意数目的列(GROUP BY中嵌套GROUP BY)。
- 如果在GROUP BY子句中嵌套了分组,数据将在最后指定的分组上进行汇总。
- GROUP BY子句中列出的每一列必须是检索列或有效的表达式(但不能是聚集函数)。如果在select中使用表达式,则必须在GROUP BY子句指定相同的表达式。不能使用别名。关于不能使用别名,但会出现MySQL允许使用别名的现象。
不能使用的原因是sql执行查询顺序导致的。from>where>group by>having>order by>select >limit。可以看到,
select
是在group by
和having
之后才执行的,这导致group by
的时候还没有别名呢,因为别名是在select
中生成的,而select
是在group by
之后,这样就会出错。#查找订单表中每个客户的消费情况 SELECT user_id,quantity*item_price AS num_pri FROM orderitems GROUP BY user_id,num_pri;
除聚集计算语句外,SELECT语句中的每一列都必须在GROUP BY子句中给出
GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。
大多数SQL实现不允许GROUP BY列带有长度可变的数据类型。
注意:一般在使用GROUP BY子句时,也应该给出ORDER BY 子句。这是保证数据正确排序的唯一方法。
#筛选订单供应商
SELECT user_id,count(*)
FROM orderitems
GROUP BY user_id
ORDER BY COUNT(*)
7.2过滤分组(HAVING)
WHERE与HAVING的唯一差别:WHERE过滤行,而HAVING过滤分组。
#筛选订单超过2次的供应商
SELECT user_id,COUNT(*)
FROM orderitems
GROUP BY user_id
HAVING COUNT(*) >= 2
ORDER BY COUNT(*);
8.使用子查询
所谓子查询是嵌套在其它查询中的查询。任何SQL语句都是查询。但此术语一般是指SELECT语句。作为子查询的SELECT语句只能查询单个列。在实际应用中由于性能的限制,不可使用太多子查询。
#订购物品RGAN01的所有顾客信息
SELECT * FROM customers WHERE cust_id IN (
SELECT cust_id FROM orders WHERE order_num IN(
SELECT order_num FROM orderitems WHERE prod_id='RGAN01'
)
)
#显示顾客表中每个顾客的订单总数
select cust_id,
cust_name,
(select count(*) from orders where orders.cust_id = customers.cust_id) as orders
from customers
ORDER by cust_name;
9.联结表(JOIN)
联结是一种机制,用来在一条SELECT语句中关联表,因此称为联结。许多DBMS处理联结远比处理子查询快得多。
笛卡尔积:由没有联结条件的表关系返回的结果为笛卡尔积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。例如以下SQL文,检索结果件数为表的行数的乘积。
#笛卡尔积
SELECT vend_name,prod_name,prod_price FROM vendors,products;
#返回笛卡尔积的联结也称叉联结(CROSS JOIN)
SELECT vend_name,prod_name,prod_price FROM vendors CROSS JOIN products;
9.1内联结
内连结也称为等值联结,它基于两个表之间的相等测试。
#等值联结
SELECT vend_name,prod_name,prod_price
FROM vendors,products
WHERE vendors.vend_id = products.vend_id;
#改用INNER JOIN写法
SELECT vend_name,prod_name,prod_price
FROM vendors
INNER JOIN products
ON vendors.vend_id = products.vend_id;
#等值联结:显示订单20007的物品供应商、物品名称、物品价格
SELECT vend_name,prod_name,prod_price
FROM vendors, products ,orderItems
WHERE vendors.vend_id = products.vend_id
AND orderItems.prod_id = products.prod_id
AND order_num = 20007;
#改用INNER JOIN写法
SELECT vend_name,prod_name,prod_price
FROM vendors
INNER JOIN products
INNER JOIN orderItems
ON vendors.vend_id = products.vend_id
AND orderItems.prod_id = products.prod_id
AND order_num = 20007;
内联结条件用特定的ON子句而不是WHERE子句给出。实际上传递的条件是一样的。
#返回顾客名称、订单号以及每个订单的总价
SELECT cust_name,orderitems.order_num,
SUM(orderitems.quantity*orderitems.item_price) AS OrderTotal
FROM customers
INNER JOIN orders
INNER JOIN orderitems
ON customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num
GROUP BY orderitems.order_num
ORDER BY cust_name,orderitems.order_num;
#返回购物总价超过1000的订单编号以及顾客名称
SELECT cust_name,orderitems.order_num,
SUM(orderitems.quantity*orderitems.item_price) AS OrderTotal
FROM customers
INNER JOIN orders
INNER JOIN orderitems
ON customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num
GROUP BY orderitems.order_num
HAVING OrderTotal>1000
ORDER BY cust_name,orderitems.order_num;
9.2自联结(self-join)
自联结用来代替从相同表检索数据的子查询语句。比如以下子查询:
#使用子查询查找与Jim Jones同一公司的所有顾客
SELECT cust_id,cust_name,cust_contact
FROM customers
WHERE cust_name = (SELECT cust_name
FROM customers
WHERE cust_contact='Jim Jones'
);
#使用自联结查找与Jim Jones同一公司的所有顾客
SELECT c1.cust_id,c1.cust_name,c1.cust_contact
FROM customers AS c1,customers AS c2
WHERE c1.cust_name = c2.cust_name
AND c1.cust_contact = 'Jim Jones';
#改用INNER JOIN写法
SELECT c1.cust_id,c1.cust_name,c1.cust_contact
FROM customers AS c1
INNER JOIN customers AS c2
ON c1.cust_name = c2.cust_name
AND c1.cust_contact = 'Jim Jones';
9.3外联结(outer join)
左外联结、右外联结
#查找没有订单顾客在内的所有顾客
SELECT c.cust_id,o.order_num
FROM customers AS c
LEFT OUTER JOIN orders AS o
ON c.cust_id = o.cust_id;
#查找产品名称和与之相关的订单总数
SELECT Products.prod_name,COUNT(order_num)
FROM Products LEFT OUTER JOIN OrderItems
ON Products.prod_id = OrderItems.prod_id
GROUP BY Products.prod_id
ORDER BY Products.prod_name;
#列出供应商及其可供产品的数量,包括没有产品的供应商
SELECT vendors.vend_id,COUNT(prod_id)
FROM vendors LEFT OUTER JOIN Products
ON vendors.vend_id = Products.vend_id
GROUP BY vendors.vend_id;
10.插入数据
INSERT SELECT 语句插入;表内容复制;
11.约束
约束的作用是管理如何插入或处理数据库数据。DBMS通过在数据库表上施加约束来实施引用完整性。
11.1主键
1.1.1主键章节
11.2外键
外键是表中的一列,其值必须列在另一表的主键中。外键是保证引用完整性的重要部分。具体体现为以下两种:
orders表的cust_id列被设定为外键,该列的合法值为customers表的主键的任一值。
1.更新cust_id列的值为customers表不存在的顾客id时,该更新语句无效。
2. 删除cust_id列的值为customers表存在的顾客id时,该更新语句无效。
因为利用外键可以防止意外删除数据。有的DBMS支持级联删除。启用级联删除时,从一个表中删除行时,任何关联表的数据也会被自动删除。
11.3唯一约束
唯一约束用来保证一列或一组列中的数据是唯一的。有相同数据更新时是不被允许的。它类似主键,但和主键的区别有以下:
- 表可包含多个唯一约束,但每个表只允许一个主键。
- 唯一约束列可包含NULL值
- 唯一约束列可修改或更新
- 唯一约束列的值可重复使用(例:雇员ID不可重复使用。离职后新入职员工不可延用)
- 唯一约束不可用来定义外键
11.4检查约束
检查约束用来保证一列或一组列中的数据满足一组指定的条件。利用这个约束,任何插入或更新的行都会被检查。
12.索引
索引用来排序数据以加快搜索和排序操作的速度。
在一个或多个列上定义索引,使DSMS保存其内容的一个排过序的列表。在检索数据时,DBMS搜索排过序的索引,找出匹配的位置,然后检索这些行。
在开始创建索引前,应明白以下:
- 索引改善了检索操作的性能,但降低了数据插入、修改和删除的性能。因为在执行表更新操作时,DBMS需要动态地更新索引。
- 索引数据可能要占用大量的存储空间
- 具有更多可能值的数据更适合做索引
- 索引用于数据过滤或数据排序
- 创建组合索引后,仅在组合列的顺序排序时有用。如果按组合列中单独的某一列进行排序,则组合索引没有用处。
索引的效率随着表数据的增加或改变而变化。因此最好定期检查索引,并根据需要对索引进行调整。