数据库存储引擎
(更多详见)
一 什么是存储引擎
mysql中建立的库===>文件夹
库中建立的表===>文件
现实生活中我们用来存储数据的文件应该有不同的类型:比如存文本用txt类型,存表格用excel,存图片用png等
数据库中的表也应该有不同的类型,表的类型不同,会对应mysql不同的存取机制,表类型又称为存储引擎。
存储引擎说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方
法。因为在关系数据库中数据的存储是以表的形式存储的,所以存储引擎也可以称为表类型(即存储和
操作此表的类型)
——(所以引擎不同,操作语法、可以实现的功能,也不尽相同)——
在Oracle 和SQL Server等数据库中只有一种存储引擎,所有数据存储管理机制都是一样的。而MySql
数据库提供了多种存储引擎。用户可以根据不同的需求为数据表选择不同的存储引擎,用户也可以根据
自己的需要编写自己的存储引擎
二 mysql支持的存储引擎
MariaDB [(none)]> show enginesG #查看所有支持的存储引擎 MariaDB [(none)]> show variables like 'storage_engine%'; #查看正在使用的存储引擎
MySQL常用的存储引擎
MyISAM存储引擎
由于该存储引擎不支持事务、也不支持外键,所以访问速度较快。因此当对事务完整性没有要求并以访问为主的应用适合使用该存储引擎。
InnoDB存储引擎(主要使用)
由于该存储引擎在事务上具有优势,即支持具有提交、回滚及崩溃恢复能力等事务特性,所以比MyISAM存储引擎占用更多的磁盘空间。因此当需要频繁的更新、删除操作,同时还对事务的完整性要求较高,需要实现并发控制,建议选择。
MEMORY
MEMORY存储引擎存储数据的位置是内存,因此访问速度最快,但是安全上没有保障。适合于需要快速的访问或临时表。
BLACKHOLE
黑洞存储引擎,可以应用于主备复制中的分发主库。
三 使用存储引擎
方法1:建表时指定
MariaDB [db1]> create table innodb_t1(id int,name char)engine=innodb; MariaDB [db1]> create table innodb_t2(id int)engine=innodb; MariaDB [db1]> show create table innodb_t1; MariaDB [db1]> show create table innodb_t2;
方法2:在配置文件中指定默认的存储引擎
/etc/my.cnf [mysqld] default-storage-engine=INNODB innodb_file_per_table=1
查看
[root@egon db1]# cd /var/lib/mysql/db1/ [root@egon db1]# ls db.opt innodb_t1.frm innodb_t1.ibd innodb_t2.frm innodb_t2.ibd
联合主键
--主键特点:非空且唯一 --1、每张表只能有一个主键 --2、每一张表不一定只有一个非空且唯一的字段 --3、如果表中只有一个非空且唯一字段,那它就是主键 ------如果表中不只有一个非空且唯一字段,那第一个非空切唯一的字段就是主键
--联合主键 CREATE TABLE book2author( id INT NOT NULL UNIQUE AUTO_INCREMENT, book_id INT, author_id INT, PRIMARY KEY (book_id,author_id) )
这样创建的主键就是联合主键,book_id 和 author_id 共同组成表的主键,这样就可以在book 和author 多对多的情况下,
在此表中,既不会存在完全重复的记录,造成无用的重复数据,也不会使得重要数据为空,导致数据无效。
索引
一 索引简介
索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构。索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要。
索引优化应该是对查询性能优化最有效的手段了。
索引能够轻易将查询性能提高好几个数量级。
索引相当于字典的音序表,如果要查某个字,如果不使用音序表,则需要从几百页中逐页去查。
索引特点:创建与维护索引会消耗很多时间与磁盘空间,但查询速度大大提高!
二 索引语法
创建索引
--创建表时 --语法: CREATE TABLE 表名 ( 字段名1 数据类型 [完整性约束条件…], 字段名2 数据类型 [完整性约束条件…], [UNIQUE] INDEX | KEY [索引名] (字段名[(长度)] [ASC |DESC]) ); --------------------------------
创建普通索引示例、唯一索引示例、全文索引示例、多列索引示例:
主键索引,主键其实也是索引
--创建普通索引示例: CREATE TABLE emp1 ( id INT, name VARCHAR(30) , resume VARCHAR(50), INDEX index_emp_name (name) --KEY index_dept_name (dept_name) ); --创建唯一索引示例: CREATE TABLE emp2 ( id INT, name VARCHAR(30) , bank_num CHAR(18) UNIQUE , resume VARCHAR(50), UNIQUE INDEX index_emp_name (name) ); --创建全文索引示例: CREATE TABLE emp3 ( id INT, name VARCHAR(30) , resume VARCHAR(50), FULLTEXT INDEX index_resume (resume) ); --创建多列索引示例: CREATE TABLE emp4 ( id INT, name VARCHAR(30) , resume VARCHAR(50), INDEX index_name_resume (name,resume) ); --主键索引,主键其实也是索引 ---------------------------------
添加和删除索引
---添加索引 ---CREATE在已存在的表上创建索引 CREATE [UNIQUE] INDEX 索引名 ON 表名 (字段名[(长度)] [ASC |DESC]) ; ---ALTER TABLE在已存在的表上创建索引 ALTER TABLE 表名 ADD [UNIQUE] INDEX 索引名 (字段名[(长度)] [ASC |DESC]) ; CREATE INDEX index_emp_name on emp1(name); ALTER TABLE emp2 ADD UNIQUE INDEX index_bank_num(band_num); -- 删除索引 语法:DROP INDEX 索引名 on 表名 DROP INDEX index_emp_name on emp1; DROP INDEX bank_num on emp2;
三 索引测试实验
--这里用到了mysql的**循环**语句,循环添加50万个数据 --创建表 create table Indexdb.t1(id int,name varchar(20)); --存储过程 delimiter $$ create procedure autoinsert() BEGIN declare i int default 1; while(i<500000)do insert into Indexdb.t1 values(i,'yuan'); set i=i+1; end while; END$$ delimiter ; --调用函数 call autoinsert(); -- 花费时间比较: -- 创建索引前 select * from Indexdb.t1 where id=300000;--0.32s -- 添加索引 create index index_id on Indexdb.t1(id); -- 创建索引后 select * from Indexdb.t1 where id=300000;--0.00s
pymsql
pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同。
一、下载安装:
pip3 install pymysql
二、使用
1、执行SQL
#!/usr/bin/env python # -*- coding:utf-8 -*- import pymysql # 创建连接 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') # 创建游标 cursor = conn.cursor() # 执行SQL,并返回收影响行数 effect_row = cursor.execute("update hosts set host = '1.1.1.2'") # 执行SQL,并返回受影响行数 #effect_row = cursor.execute("update hosts set host = '1.1.1.2' where nid > %s", (1,)) # 执行SQL,并返回受影响行数 #effect_row = cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)]) # 提交,不然无法保存新建或者修改的数据 conn.commit() # 关闭游标 cursor.close() # 关闭连接 conn.close()
2、获取新创建数据自增ID
#!/usr/bin/env python # -*- coding:utf-8 -*- import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') cursor = conn.cursor() cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)]) conn.commit() cursor.close() conn.close() # 获取最新自增ID new_id = cursor.lastrowid
3、获取查询数据
#!/usr/bin/env python # -*- coding:utf-8 -*- import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') cursor = conn.cursor() cursor.execute("select * from hosts") # 获取第一行数据 row_1 = cursor.fetchone() # 获取前n行数据 # row_2 = cursor.fetchmany(3) # 获取所有数据 # row_3 = cursor.fetchall() conn.commit() cursor.close() conn.close()
注:在fetch数据时按照顺序进行,可以使用cursor.scroll(num,mode)来移动游标位置,如:
- cursor.scroll(1,mode='relative') # 相对当前位置移动
- cursor.scroll(2,mode='absolute') # 相对绝对位置移动
4、fetch数据类型
关于默认获取的数据是元祖类型,如果想要或者字典类型的数据,即:
#!/usr/bin/env python # -*- coding:utf-8 -*- import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') # 游标设置为字典类型 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) r = cursor.execute("call p1()") result = cursor.fetchone() conn.commit() cursor.close() conn.close()
SQLAchemy
SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
SQLAlchemy本身无法操作数据库,其必须以来pymsql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作,如:
MySQL-Python mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname> pymysql mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>] MySQL-Connector mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname> cx_Oracle oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...] 更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html
一、底层处理
使用 Engine/ConnectionPooling/Dialect 进行数据库操作,Engine使用ConnectionPooling连接数据库,然后再通过Dialect执行SQL语句。
#!/usr/bin/env python # -*- coding:utf-8 -*- from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=5) # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES ('1.1.1.22', 3)" # ) # 新插入行自增ID # cur.lastrowid # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES(%s, %s)",[('1.1.1.22', 3),('1.1.1.221', 3),] # ) # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES (%(host)s, %(color_id)s)", # host='1.1.1.99', color_id=3 # ) # 执行SQL # cur = engine.execute('select * from hosts') # 获取第一行数据 # cur.fetchone() # 获取第n行数据 # cur.fetchmany(3) # 获取所有数据 # cur.fetchall()
二、ORM功能使用
ORM框架的作用就是把数据库表的一行记录与一个对象互相做自动转换。 正确使用ORM的前提是了解关系数据库的原理。 ORM就是把数据库表的行与相应的对象建立关联,互相转换。 由于关系数据库的多个表还可以用外键实现一对多、多对多等关联,相应地, ORM框架也可以提供两个对象之间的一对多、多对多等功能。
1 创建表
#coding:utf8 import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String from sqlalchemy.orm import sessionmaker print(sqlalchemy.__version__) engine = create_engine('sqlite:///dbyuan111.db', echo=True)#1 连接数据库 Base = declarative_base()#2 生成一个SQLORM基类 class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String) fullname = Column(String) password = Column(String) def __repr__(self): return "<User(name='%s', fullname='%s', password='%s')>" % ( self.name, self.fullname, self.password) Base.metadata.create_all(engine) #3 创建所有表结构 ed_user = User(name='xiaoyu', fullname='Xiaoyu Liu', password='123') # print(ed_user) #3 这两行触发sessionmaker类下的__call__方法,return得到 Session实例,赋给变量session,所以session可以调用Session类下的add,add_all等方法 MySession = sessionmaker(bind=engine) session = MySession() # session.add(ed_user) # our_user = session.query(User).filter_by(name='ed').first() # SELECT * FROM users WHERE name="ed" LIMIT 1; # session.add_all([ # User(name='alex', fullname='Alex Li', password='456'), # User(name='alex', fullname='Alex old', password='789'), # User(name='peiqi', fullname='Peiqi Wu', password='sxsxsx')]) # session.commit() #print(">>>",session.query(User).filter_by(name='ed').first()) #print(session.query(User).all()) #order_by前不加all() # for row in session.query(User).order_by(User.id): # print('<<',row) # for row in session.query(User).filter(User.name.in_(['alex', 'wendy', 'jack'])):#这里的名字是完全匹配 # print(row) # for row in session.query(User).filter(~User.name.in_(['ed', 'wendy', 'jack'])): # print(row) #print(session.query(User).filter(User.name == 'ed').count()) #from sqlalchemy import and_, or_ # for row in session.query(User).filter(and_(User.name == 'ed', User.fullname == 'Ed Jones')): # print(row) # for row in session.query(User).filter(or_(User.name == 'ed', User.name == 'wendy')): # print(row) 单表
# #coding:utf8 # # import sqlalchemy # from sqlalchemy import create_engine # from sqlalchemy.ext.declarative import declarative_base # from sqlalchemy import Column, Integer, String,ForeignKey # from sqlalchemy.orm import sessionmaker,relationship # # # engine = create_engine('sqlite:///dbyuan2.db', echo=True) # # Base = declarative_base() # #多对多:创建第三张表 # class Author2Book(Base): # __tablename__='author2book' # # nid=Column(Integer,primary_key=True) # author_id=Column(Integer,ForeignKey("author.id")) # book_id=Column(Integer,ForeignKey("book.id")) # # # class Publisher(Base): # __tablename__ = 'publisher' # #id = Column(Integer, primary_key=True)里的数据类型一定写整型(Integer) # id = Column(Integer, primary_key=True) # name = Column(String(20)) # city = Column(String(20)) # country = Column(String(20)) # # # def __str__(self): # return self.name # # class Author(Base): # __tablename__ = 'author' # id = Column(Integer, primary_key=True) # name = Column(String(20)) # # def __str__(self): # return self.name # # class AuthorDetail(Base): # __tablename__ = 'author_detail' # # id = Column(Integer, primary_key=True) # sex = Column(String(20),default='male') # email =Column(String(20),default='123@qq.com') # address = Column(String(20),default='beijing') # birthday =Column(String(20)) # author = Column(String(20),ForeignKey('author.id'),unique=True)#一对一 # # class Book(Base): # __tablename__ = 'book' # # id = Column(Integer, primary_key=True) # title = Column(String(20)) # publisher_id = Column(String(20),ForeignKey('publisher.id'))#一对多 # publication_date = Column(String(20)) # price=Column(String(20)) # # def __str__(self): # return self.title # # # # # Base.metadata.create_all(engine) # # Session = sessionmaker(bind=engine) # session = Session() # # # b1= Book(title='PHP',publisher_id=1,publication_date='2016-8-24',price=100) # b2= Book(title='python',publisher_id=3,publication_date='2017-8-24',price=210) # b3= Book(title='java',publisher_id=2,publication_date='2018-8-24',price=90) # # a1=Author(name='alex') # a2=Author(name='alvin') # # ad1=AuthorDetail(birthday='1980-2-16',author=1) # ad2=AuthorDetail(birthday='1990-3-16',author=1) # # # p1=Publisher(name='北大出版社',city='北京',country='中国') # p2=Publisher(name='河大出版社',city='保定',country='中国') # p3=Publisher(name='中国机械出版社',city='北京',country='中国') # # ab1=Author2Book(author_id=1,book_id=1) # ab2=Author2Book(author_id=1,book_id=2) # ab3=Author2Book(author_id=2,book_id=2) # # # session.add_all([a1,a2,ad1,ad2,b1,b2,b3,p1,p2,p3,ab1,ab2,ab3]) # session.commit() #################################################### #很明显,这种建立表关系的方式不够直接和简单. #coding:utf8 import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String,ForeignKey from sqlalchemy.orm import sessionmaker,relationship engine = create_engine('sqlite:///dbyuan242246.db', echo=True) Base = declarative_base() #多对多:创建第三张表 class Author2Book(Base): __tablename__='author2book' nid=Column(Integer,primary_key=True) author_id=Column(Integer,ForeignKey("author.id")) book_id=Column(Integer,ForeignKey("book.id")) class Publisher(Base): __tablename__ = 'publisher' #id = Column(Integer, primary_key=True)里的数据类型一定写整型(Integer) id = Column(Integer, primary_key=True) name = Column(String(20)) city = Column(String(20)) country = Column(String(20)) def __str__(self): return self.name class Author(Base): __tablename__ = 'author' id = Column(Integer, primary_key=True) name = Column(String(20)) book_obj_list=relationship('Book',secondary=Author2Book.__table__,backref='author_obj_list')#多对多的relationship如是写,有一个secondary def __str__(self): return self.name class AuthorDetail(Base): __tablename__ = 'author_detail' id = Column(Integer, primary_key=True) sex = Column(String(20),default='male') email =Column(String(20),default='123@qq.com') address = Column(String(20),default='beijing') birthday =Column(String(20)) author = Column(String(20),ForeignKey('author.id'),unique=True)#一对一 class Book(Base): __tablename__ = 'book' id = Column(Integer, primary_key=True) title = Column(String(20)) publisher_id = Column(String(20),ForeignKey('publisher.id'))#一对多 publisher_obj_list=relationship('Publisher',backref='book_obj_list')#一对多的relationship如是写 publication_date = Column(String(20)) price=Column(String(20)) def __str__(self): return self.title Base.metadata.create_all(engine) Session = sessionmaker(bind=engine) session = Session() #publisher_id不用加上啦 b1= Book(title='PHP',publication_date='2016-8-24',price=100) b2= Book(title='python',publication_date='2017-8-24',price=210) b3= Book(title='java',publication_date='2018-8-24',price=90) a1=Author(name='alex') a2=Author(name='alvin') ad1=AuthorDetail(birthday='1980-2-16',author=1) ad2=AuthorDetail(birthday='1990-3-16',author=2) p1=Publisher(name='北大出版社',city='北京',country='中国') p2=Publisher(name='河大出版社',city='保定',country='中国') p3=Publisher(name='中国机械出版社',city='北京',country='中国') # ab1=Author2Book(author_id=1,book_id=1) # ab2=Author2Book(author_id=1,book_id=2) # ab3=Author2Book(author_id=2,book_id=2) #第三张表就不用插入数据了 #建立多对多的关系,增加关系用append:b1.author_obj_list.append([a1,a2]) b1.author_obj_list=[a1,a2] b2.author_obj_list=[a1,a2] b1.publisher_obj_list=p1 # b1.publisher_obj_list=[p1,p2,p3]这样会报错,因为一对多的关系,b1.publisher_obj_list不可能绑定多个对象,反过来可以,如下 p1.book_obj_list=[b1,b2,b3] ''' 大家思考:b1.publisher_obj_list=p1与p1.book_obj_list=b1效果相同吗? 其实是一样的,举个例子:书法协会作为一个团体招人,alex也想进入该协会,两个动作都可以完成这件事: 书法协会作为主体把alex招了进来 alex作为主体加入了该组织 ''' ''' 注意点: ret = session.query(Users).all() 有all().first()等,ret是对象列表;没有,则是sql语句 关联查询 r = session.query(Book.title,Publisher.name).join(Publisher).all() r = session.query(Author2Book).join(Author).all() ''' session.add_all([a1,a2,ad1,ad2,b1,b2,b3,p1,p2,p3]) session.commit()
2 操作表
session.query(Users).filter(Users.id > 2).delete()
session.commit()
session.query(Users).filter(Users.id > 2).update({"name" : "099"}) session.query(Users).filter(Users.id > 2).update({Users.name: Users.name + "099"}, synchronize_session=False) session.query(Users).filter(Users.id > 2).update({"num": Users.num + 1}, synchronize_session="evaluate") session.commit()
ret = session.query(Users).all() ret = session.query(Users.name, Users.extra).all() ret = session.query(Users).filter_by(name='alex').all() ret = session.query(Users).filter_by(name='alex').first()
# 条件 ret = session.query(Users).filter_by(name='alex').all() ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all() ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric').all() ret = session.query(Users).filter(Users.id.in_([1,3,4])).all() ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all() ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all() from sqlalchemy import and_, or_ ret = session.query(Users).filter(and_(Users.id > 3, Users.name == 'eric')).all() ret = session.query(Users).filter(or_(Users.id < 2, Users.name == 'eric')).all() ret = session.query(Users).filter( or_( Users.id < 2, and_(Users.name == 'eric', Users.id > 3), Users.extra != "" )).all() # 通配符 ret = session.query(Users).filter(Users.name.like('e%')).all() ret = session.query(Users).filter(~Users.name.like('e%')).all() # 限制 ret = session.query(Users)[1:2] # 排序 ret = session.query(Users).order_by(Users.name.desc()).all() ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all() # 分组 from sqlalchemy.sql import func ret = session.query(Users).group_by(Users.extra).all() ret = session.query( func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.name).all() ret = session.query( func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.name).having(func.min(Users.id) >2).all() # 连表 ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all() ret = session.query(Person).join(Favor).all() ret = session.query(Person).join(Favor, isouter=True).all() # 组合 q1 = session.query(Users.name).filter(Users.id > 2) q2 = session.query(Favor.caption).filter(Favor.nid < 2) ret = q1.union(q2).all() q1 = session.query(Users.name).filter(Users.id > 2) q2 = session.query(Favor.caption).filter(Favor.nid < 2) ret = q1.union_all(q2).all() 其它