mysql存储过程 delete select insert_数据库操作优化(insert、update、delete、select)

一、insert优化:

要操作的表为test,字段test。这里优化的方式是先组合一条多行的sql语句,然后再进行插入操作,这样就很大程度上优化了插入数据的效率。

测试代码如下:

$sql = "insert into `test` (`test`) values

('$content')";

for ($i=1;$i<999;$i++) {

$sql .= ",('$content')";

}

mysql_query($sql);

执行时间为:

0.0323481559753

0.0371758937836

0.0419669151306

更多的说明:

起因:有一个innoDB引擎的表Table,在一个大概3000次的foreach循环中执行

INSERT INTO Table(columnA, columnB) VALUES (valueA,

valueB)

结果居然超出了60S的php执行限制(当然这个限制可以在php.ini中修改),让我很不解为何插入效率如此低下。

经过查找资料以及摸索,得到以下优化方法:

1、innoDB是mysql引擎中唯一支持事务transaction的引擎。默认所有用户行为都在事务内发生。

默认mysql建立新连接时,innoDB采用自动提交autocommit模式,每个SQL语句在它自己上形成一个单独的事务,即insert一次就commit了一次,InnoDB在该事务提交时必须刷新日志到磁盘,因此效率受限于磁盘读写效率。

你可以通过

mysql_query("SET AUTOCOMMIT = 0");

来关闭自动提交模式。

如 果自动提交模式被关闭,那么我们可以认为一个用户总是有一个事务打开着。一个SQL

COMMIT或ROLLBACK语句结束当前事务并且一个新事务开始。两个语句都释放所有在当前事务中被设置的InnoDB锁定。一个COMMIT语句意

味着在当前事务中做的改变被生成为永久的,并且变成其它用户可见的。一个ROLLBACK语句,在另一方面,撤销所有当前事务做的修改。

当然如果是自动提交模式,通过用明确的START

TRANSACTION或BEGIN语句来开始一个事务,并用COMMIT或者ROLLBACK语句来结束它,这样用户仍旧可以执行一个多重语句事务。

2、因此对于本例,在建立数据库连接后,立即关闭自动提交,在foreach循环结束后,一次commit即可,效率大大提升。

mysql_query("SET AUTOCOMMIT = 0");

foreach(***)

INSERT INTO Table(columnA, columnB) VALUES

(valueA, valueB)

mysql_query("commit");

3、对于多次insert行到同一表的需求,你还可以采用多行插入语法来减少客户端和服务器之间的通讯开支。

INSERT INTO Table(columnA, columnB) VALUES (1,2), (5,5),

(3,3), ...

4、如果你的表有索引,索引会拖慢insert速度。大量插入数据时,可以先关闭索引,然后再重建索引。

ALTER TABLE Table DISABLE KEYS;

INSERT INTO ***;

ALTER TABLE Table ENABLE KEYS;

二、update优化:

三、select优化:

使用索引优化查询:

2.索引作用

在索引列上,除了上面提到的有序查找之外,数据库利用各种各样的快速定位技术,能够大大提高查询效率。特别是当数据量非常大,查询涉及多个表时,使用索引往往能使查询速度加快成千上万倍。

例如,有3个未索引的表t1、t2、t3,分别只包含列c1、c2、c3,每个表分别含有1000行数据组成,指为1~1000的数值,查找对应值相等行的查询如下所示。

SELECT c1,c2,c3 FROM t1,t2,t3 WHERE c1=c2 AND

c1=c3

此查询结果应该为1000行,每行包含3个相等的值。在无索引的情况下处理此查询,必须寻找3个表所有的组合,以便得出与WHERE子句相配的那些行。而可能的组合数目为1000×1000×1000(十亿),显然查询将会非常慢。

如果对每个表进行索引,就能极大地加速查询进程。利用索引的查询处理如下。

(1)从表t1中选择第一行,查看此行所包含的数据。

(2)使用表t2上的索引,直接定位t2中与t1的值匹配的行。类似,利用表t3上的索引,直接定位t3中与来自t1的值匹配的行。

(3)扫描表t1的下一行并重复前面的过程,直到遍历t1中所有的行。

在此情形下,仍然对表t1执行了一个完全扫描,但能够在表t2和t3上进行索引查找直接取出这些表中的行,比未用索引时要快一百万倍。

利用索引,MySQL加速了WHERE子句满足条件行的搜索,而在多表连接查询时,在执行连接时加快了与其他表中的行匹配的速度。

13.4.2 创建索引

在执行CREATE TABLE语句时可以创建索引,也可以单独用CREATE

INDEX或ALTER TABLE来为表增加索引。

1.ALTER TABLE

ALTER TABLE用来创建普通索引、UNIQUE索引或PRIMARY

KEY索引。

ALTER TABLE table_name ADD INDEX index_name

(column_list)

ALTER TABLE table_name ADD UNIQUE

(column_list)

ALTER TABLE table_name ADD PRIMARY KEY

(column_list)

其中table_name是要增加索引的表名,column_list指出对哪些列进行索引,多列时各列之间用逗号分隔。索引名index_name可选,缺省时,MySQL将根据第一个索引列赋一个名称。另外,ALTER TABLE允许在单个语句中更改多个表,因此可以在同时创建多个索引。

2.CREATE INDEX

CREATE INDEX可对表增加普通索引或UNIQUE索引。

CREATE INDEX index_name ON table_name

(column_list)

CREATE UNIQUE INDEX index_name ON table_name

(column_list)

table_name、index_name和column_list具有与ALTER

TABLE语句中相同的含义,索引名不可选。另外,不能用CREATE INDEX语句创建PRIMARY

KEY索引。

3.索引类型

在创建索引时,可以规定索引能否包含重复值。如果不包含,则索引应该创建为PRIMARY

KEY或UNIQUE索引。对于单列惟一性索引,这保证单列不包含重复的值。对于多列惟一性索引,保证多个值的组合不重复。

PRIMARY KEY索引和UNIQUE索引非常类似。事实上,PRIMARY

KEY索引仅是一个具有名称PRIMARY的UNIQUE索引。这表示一个表只能包含一个PRIMARY

KEY,因为一个表中不可能具有两个同名的索引。

下面的SQL语句对students表在sid上添加PRIMARY

KEY索引。

ALTER TABLE students ADD PRIMARY KEY

(sid)

13.4.3 删除索引

可利用ALTER TABLE或DROP

INDEX语句来删除索引。类似于CREATE

INDEX语句,DROP INDEX可以在ALTER

TABLE内部作为一条语句处理,语法如下。

DROP INDEX index_name ON

talbe_name

ALTER TABLE table_name DROP INDEX

index_name

ALTER TABLE table_name DROP PRIMARY

KEY

其中,前两条语句是等价的,删除掉table_name中的索引index_name。

第3条语句只在删除PRIMARY

KEY索引时使用,因为一个表只可能有一个PRIMARY KEY索引,因此不需要指定索引名。如果没有创建PRIMARY KEY索引,但表具有一个或多个UNIQUE索引,则MySQL将删除第一个UNIQUE索引。

如果从表中删除了某列,则索引会受到影响。对于多列组合的索引,如果删除其中的某列,则该列也会从索引中删除。如果删除组成索引的所有列,则整个索引将被删除。

13.5.1 使用INSERT增加记录

向表中增加新记录有以下几种方法。

a4c26d1e5885305701be709a3d33442f.png

通过INSERT语句将记录插入表中;

a4c26d1e5885305701be709a3d33442f.png

通过从某个文件读取数据来增加记录,可以利用LOAD DATA或mysqlimport实用程序装入数据,也可以预先写成多个INSERT语句的形式。

本节将首先介绍使用INSERT语句。使用INSERT语句,需要指定接收数据的表,以及所要增加的数据,具有以下几种形式。

1.给出所有列的值

语法如下。

INSERT INTO table_name

VALUES(value1,value2,...)

例如:

#向students表中添加两个学生记录张三

mysql> INSERT INTO students

VALUES

-> (1,'张三','男',21);

#向courses表中添加三个课程记录C语言

mysql> INSERT INTO courses

VALUES

-> (1,'C语言',3,'李老师');

#向stu_cou表中添加张三和李四的成绩信息

mysql> INSERT INTO stu_cou

VALUES

-> ( 1,2,90 );

其中,VALUES必须包含表中每列的值,并且按表中列的存放次序依次给出。在MySQL 中,需要用单引号或双引号将串和日期值括起来。如果某一列为AUTO_INCREMENT,则可赋值为NULL。

另外,利用单个的INSERT语句可以一次将几行插入一个表中。

INSERT INTO table_name VALIUES

(...),(...),...

如下所示:

mysql> INSERT INTO students

VALUES

-> (1,'张三','男',21),

-> (2,'李四','男',22);

2.给出要赋值的列,然后再给出值

语法如下。

INSERT INTO

table_name(column_name1,column_name2,...) VALUES(value1,

value1,...)

这种方式适用于只给表中的某些列赋值,例如:

mysql> INSERT INTO

courses(cid,cname,ccredit) VALUES

-> (1,'C语言',3);

同样,也可以一次添加多个记录:

mysql> INSERT INTO

courses(cid,cname,ccredit) VALUES

-> (1,'C语言',3);

-> (2,'数据结构',2);

对于未指定的列,所添加的指为默认值,或NULL。

3.用col_name =

value 的形式给出列和值

语法如下。

INSERT INTO table_name SET

column_name1=value1,column_name2=value2,...

例如:

mysql> INSERT INTO courses

SET

-> (cid=1,,cname='C语言',ccredit=3);

使用这种形式的INSERT不能一次插入多行数据。

13.5.2 使用LOAD

DATA批量增加记录

从文件读取数据可以将大量记录装载到表中。LOAD DATA语句可以批量装载数据,它从一个文件中读取数据。

mysql> LOAD DATA LOCAL

INFILE "students_data.txt" INTO TABLE students;

该语句读取客户机当前目录中数据文件students_data.txt的内容,并将其发送到服务器并装入students表。缺省时,LOAD

DATA语句假定列值由tab键分隔,而行以换行符结束,并假定各个值是按列在表中的存放次序给出的。

13.5.3 使用mysqlimport批量增加记录

除LOAD

DATA外,还可以使用mysqlimport实用程序直接从文件读取批量数据。实际上,mysqlimport实用程序相当于LOAD

DATA 的命令行的一个接口。

从外壳程序调用mysqlimport:

% mysqlimport --local

students_coureses student.txt

Mysqlimport自动生成一个LOAD

DATA语句,此语句把student.txt文件中的数据装入student表。Mysqlimport根据数据文件名导出表名(将文件名第一个圆点前的所有字符作为表名)。例如,student.txt

将被装入student表,而president.txt将被装入president表。如果有多个需要装入单个表的文件,应仔细地确定文件名,使表名一致,如table.1.txt、table.2.txt等,否则mysqlimport

将不能使用正确的表名。

对于table1.txt与table2.txt

这样的文件名,mysqlimport将会认为相应的表名为table1和table2。

13.5.4 修改记录(UPDATE)

为了修改现有记录,可利用UPDATE语句,格式如下。

UPDATE table_name

SET

column_name1=new_value1,column_name2=new_value2,...

WHERE Condition

WHERE子句是可选的,指定所要修改的记录。如果不指定的话,表中的每个记录都被更新。下面的查询将每个学生的性别都更改为“F”。

UPDATE students SET sgender='F'

将每个学生的年龄都加1:

UPDATE students SET sage=sage+1

本节,不详细介绍WHERE字句,在下一节“查询数据”中将详细介绍。

13.5.5 删除记录(DELETE)

DELETE语句用于删除现有记录,格式如下。

DELETE FROM table_name

WHERE Condition

同UPDATE一样,WHERE子句是可选的,指定所要删除的记录。如果不指定,表中的每个记录都被删除。下面的查询将删除性别为“F”的学生。

DELETE FROM students WHERE

sgender='f'

下面的查询将删除性别为“F”并且年龄大于21的学生。

DELETE FROM students WHERE sgender='f' AND

sage>21

不带WHERE的DELETE查询将删除所有的学生。

DELETE FROM students

刚给一个朋友解决他写的Discuz!插件的问题,说到MySQL的COUNT(*)的效率,发现越说越说不清楚,干脆写下来,分享给大家。

COUNT(*)与COUNT(COL)

网上搜索了下,发现各种说法都有:

比如认为COUNT(COL)比COUNT(*)快的;

认为COUNT(*)比COUNT(COL)快的;

还有朋友很搞笑的说到这个其实是看人品的。

在不加WHERE限制条件的情况下,COUNT(*)与COUNT(COL)基本可以认为是等价的;

但是在有WHERE限制条件的情况下,COUNT(*)会比COUNT(COL)快非常多;

具体的数据参考如下:

mysql> SELECT COUNT(*) FROM cdb_posts where fid =

604;

+————+

| COUNT(fid) |

+————+

| 79000 |

+————+

1 row in set (0.03 sec)

mysql> SELECT COUNT(tid) FROM cdb_posts where fid

= 604;

+————+

| COUNT(tid) |

+————+

| 79000 |

+————+

1 row in set (0.33 sec)

mysql> SELECT COUNT(pid) FROM cdb_posts where fid

= 604;

+————+

| COUNT(pid) |

+————+

| 79000 |

+————+

1 row in set (0.33 sec)

COUNT(*)通常是对主键进行索引扫描,而COUNT(COL)就不一定了,另外前者是统计表中的所有符合的纪录总数,而后者是计算表中所有符合的COL的纪录数。还有有区别的。

COUNT时的WHERE

这点以前就写过,详细请看《Mysql中count(*),DISTINCT的使用方法和效率研究》:http://www.ccvita.com/156.html

简单说下,就是COUNT的时候,如果没有WHERE限制的话,MySQL直接返回保存有总的行数

而在有WHERE限制的情况下,总是需要对MySQL进行全表遍历。

优化总结:

1.任何情况下SELECT COUNT(*) FROM tablename是最优选择;

2.尽量减少SELECT COUNT(*) FROM tablename WHERE COL = ‘value’

这种查询;

3.杜绝SELECT COUNT(COL) FROM tablename WHERE COL2 = ‘value’ 的出现。

你可能感兴趣的:(mysql存储过程,delete,select,insert)