〖Mysql〗-- 数据库进阶

【数据库进阶】

关于连表

1
2
3
左右连表:  join
上下连表:  union    #自动去重  (当两张表里的数据,有重复的才会自动去重)
            union  all   #不去重 
1
2
3
4
5
6
7
8
#上下连表示例:
     select  sid,sname  from  sname
     union
     select  tid,tname  from  teacher
     
     select  sid,sname  from  student
     UNION  ALL
     select  sid,sname  from  student

视图 (不常用,开发过程中不长用,在开发语句中写,不要在数据库中写)

  视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,并可以将其当作表来使用。

  在一张物理表中,通过某种条件查询到的信息,重新生成一个新的虚拟表,这个表是通过创建时的语句,从物理表中实时拿取数据。

  视图不能进行增 改 操作,视图对应的原物理表数据变更的话,视图表内的数据也会改变!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#语法
创建视图:
     语法:
         create  view  视图名  AS  sql语句
     例子:
         create  view  v1  as  select  from  teacher  where  tid >2;   
删除视图:
     drop  view  视图名
更改视图:
     语法:
         alter  view  视图名  AS  sql语句
     更改视图其实更改的就是对应的sql语句
使用视图:
     使用视图时,将其当作表进行操作即可,由于视图是虚拟表,所以无法使用其对真实表进行创建、更新和删除操作,仅能做查询用。         
     select  from  v1;

触发器 (查询不会引发此操作!)

  当对某表里的某行,做增删改操作时,可在完成之前或是之后去触发执行某个操作;
  当对某表里的某行,做增删改操作时,可以使用触发器自定义关联行为。

当有相关的操作时候,每执行一次相关操作,触发器也会执行一次。触发器操作,分为执行前触发和执行之后触发!

1
CREATE  TRIGGER  tri_after_update_tb1  AFTER  UPDATE  ON  tb1  FOR  EACH ROW
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#语法:       
  增
     #在执行增加操作前:
     create  trigger  操作名字(自定义,不重复) before  insert  on  要操作的表名  for  each row
     begin
         函数体,执行sql操作的语句
     end    
     #在执行增加操作后:
     create  trigger  操作名字(自定义,不重复)  after  insert  on  要操作的表名  for  each row
     begin
         函数体,执行sql操作的语句
     end    
 
  删    
     #在执行删除操作前:
     create  trigger  操作名字(自定义,不重复) before  drop  on  要操作的表名  for  each row
     begin
         函数体,执行sql操作的语句
     end    
     
     #在执行删除操作后:
     create  trigger  操作名字(自定义,不重复)  after  drop  on  要操作的表名  for  each row
     begin
         函数体,执行sql操作的语句
     end    
     
  改
     #在执行更改操作前:
     create  trigger  操作名字(自定义,不重复) before  update  on  要操作的表名  for  each row
     begin
         函数体,执行sql操作的语句
     end    
     
     #在执行更改操作后:
     create  trigger  操作名字(自定义,不重复)  after  update  on  要操作的表名  for  each row
     begin
         函数体,执行sql操作的语句
     end  

  在定义触发器之前,可以先把sql语句终止时用分号触发执行的操作改成别的符号,然后再更改回来;当函数体中有多条更改语句的时候,每条语句之后需要用分号结尾。若想不与系统冲突,用 delimiter更改sql操作终止的标点符号,修改完之后,等操作结束再改回原分号“;” 不能影响别的操作行为。例如:delimiter //

触发器举例:

1
2
3
4
5
6
7
8
9
10
delimiter //
create  trigger  t1 BEFORE  INSERT  on  student  for  EACH ROW
     BEGIN
         INSERT  into  teacher(tname)  values (NEW.sname);
         INSERT  into  teacher(tname)  values (NEW.sname);
         INSERT  into  teacher(tname)  values (NEW.sname);
         INSERT  into  teacher(tname)  values (NEW.sname);
     END  //
     delimiter ;
insert  into  student(gender,class_id,sname)  values ( '男' ,1, '陈XX' ),( '女' ,1, '李XX' );

  NEW 代表触发器外执行对应操作,新插入代码中的数据! 常用于 insert into 插入新数据,new 获取要插入的内容 
  OLD 代表触发器外执行对应操作,对应的原代码中要变更或是要删除的数据! 常用于 删和改 drop和update

删除触发器: drop trigger 触发器名

函数

  函数执行方法:select 函数名

内置函数
1
2
3
时间格式化函数 date_format()
语法:date_format(具体时间,格式化操作时间结构,不同的占位符)
例如: date_format(ctime, "%Y-%m" ) 显示年月
自定义函数(存在于数据库中,设置好后,在python中直接调用即可)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
语法:
     数据类型 是强制型的,创建时指定的什么类型,就只能传入什么类型
     create  function  函数名(
         参数1 类型1
         参数2 类型2
         ...
     )
     returns  数据类型  #指定函数返回值的数据类型
     begin
         declare (声明变量) 变量名 数据类型  default  初始值
         函数体,执行sql操作的语句
     end
示例:
     delimiter \\
     create  function  f1(
         i1  int ,
         i2  int )
     returns  int
     BEGIN
         declare  num  int ;
         set  num = i1 + i2;
         return (num);
     END  \\
     delimiter ;

自定义函数时需注意:
  函数必须有返回值;
  函数内部不能写 select * from tb1 这种sql语句;

删除函数: drop function 函数名

存储过程

  存储过程是一个SQL语句集合,当主动去调用存储过程时,其中内部的SQL语句会按照逻辑执行。
  存储过程 可以写SQL语句!!!

  是保存在MySQL上的一个别名,他代指着很多的SQL语句操作,只要使用这个别名就能查到结果!用于替代程序员写SQL语句。为了职责更明确,可以把SQL语句放在程序里边,有以下几种操作方式:

1
2
3
4
5
6
7
8
9
方式一:
     MySQL: 存储过程
     程序:调用存储过程
方式二:
     MySQL:。。(不操作)
     程序:SQL语句
方式三:
     MySQL:。。(不操作)
     程序:类和对象(SQL语句)(ORM框架)

创建存储过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
语法:
     简单类型:
         delimiter //
         create  procedure  名字()
         begin
             SQL语句
         end //
         delimiter ;
     
     传参数:( in , out ,inout)<参数不管是否使用,都必须传值,而且存储过程是没有返回值的!!!>
         delimiter //
         create  procedure  p2(
             in  n1  int ,
             in  n2  int
         )
         BEGIN
             sql语句
         END //
         delimiter ;

执行存储过程:

1
2
3
4
SQL:call 名字()
py: cursor .callproc( "名字" ,(传参))
     cursor . commit () 一定要提交操作
     cursor .fetchall() 获取查询到的结果集

删除存储过程:

1
drop  procedure  名字;

分类举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
1. 简单
     create  procedure  p1()
     BEGIN
         select  from  student;
         INSERT  into  teacher(tname)  values ( "ct" );
     END
 
     call p1()
     cursor .callproc( 'p1' )  
2. 传参数   in   调用执行时加括号是为了预留传参( in , out ,inout)
     delimiter //
     create  procedure  p2(
         in  n1  int ,
         in  n2  int
     )
     BEGIN
         
         select  from  student  where  sid > n1;
     END  //
     delimiter ;
     
     sql:    call p2(12,2)
     py:      cursor .callproc( 'p2' ,(12,2))
3. 参数  out   用以模拟返回值 只能往回传,获取不到传入的值
     delimiter //
     create  procedure  p3(
         in  n1  int ,
         inout n2  int
     )
     BEGIN
         set  n2 = 123123;
         select  from  student  where  sid > n1;
     END  //
     delimiter ;
     
sql: set  @v1 = 10;创建并设置回话级别的变量      创建session级别变量 @     set  设置变量
     call p3(12,@v1)
     select  @v1;     打印 执行结束后的 全局变量
 
py:  cursor .callproc( 'p3' ,(12,2)) 传参
     r1 =  cursor .fetchall() 拿结果集
     print(r1)
 
     cursor . execute ( 'select @_p3_0,@_p3_1' ) 固定写法 拿取存储过程的执行结果
     r2 =  cursor .fetchall()
     print(r2)
     (等同于 sql 中的以下操作!
         set  @_p3_0 = 12 session 级别的变量
         ser @_p3_1 = 2
         call p3(@_p3_0,@_p3_1)
         select  @_p3_0,@_p3_1
     )

总结:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
=======>特性:
         a. 可传参:  in    out    inout
         b. pymysql
             1.拿结果集
                 cursor .callproc( 'p3' ,(12,2))
                 r1 =  cursor .fetchall()
                 print(r1)
             2.拿返回值
                 cursor . execute ( 'select @_p3_0,@_p3_1' )
                 r2 =  cursor .fetchall()
                 print(r2)
                             
*为什么有结果集又有 out 伪造的返回值?(主要原因:是用于判断执行SQL语句的结果!)
delimiter //
create  procedure  p3(
     in  n1  int ,
     out  n2  int   设置一个值,用于标识存储过程的执行结果  1,2
)
BEGIN   -- 执行居多的增加语句
     insert  into  表名(列名)  values ();
     insert  into  表名(列名)  values ();
     insert  into  表名(列名)  values ();
     insert  into  表名(列名)  values ();
     insert  into  表名(列名)  values ();
END  //
delimiter ;

事务

  事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。
  判断操作完成状态:执行完成就结束,有错误就回滚。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#伪代码:
     delimiter //
     create  procedure  p4(
         out  status  int
     )
     BEGIN
         1. 声明如果出现异常则执行{
             set  status = 1; 检测到错误 返回的状态值
             rollback ;  必须加上 回滚操作!
         }
         开始事务
             -- 某1账户减去100  操作
             -- 某2账户加90
             -- 某3账户加10
             commit ;  事物执行完,正确会提交!
         结束
         set  status = 2; 正常执行成功,返回状态值   
     END  //
     delimiter ;

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
delimiter //
create  PROCEDURE  p5(
     OUT  p_return_code tinyint
)
BEGIN
   DECLARE  exit handler  for  sqlexception 
   BEGIN
     -- ERROR
     set  p_return_code = 1;
     rollback ;
   END ;
  
   START  TRANSACTION -- 开始事务
     DELETE  from  tb1;
     insert  into  tb2( name ) values ( 'seven' );
   COMMIT ;
  
   -- SUCCESS
   set  p_return_code = 2;
  
   END //
delimiter ;

获取out返回结果:

1
2
3
4
5
6
7
8
sql:
     set  @v2 = 0;
     call p5(@v2);
     select  @v2;
 
py:  cursor . execute ( 'select @_p5_0' )
     r5 =  cursor .fetchall()
     print(r5)

MyISAM 和 InnoDB的区别

  MyISAM适合于一些需要大量查询的应用,但其对于有大量写操作并不是很好。甚至你只是需要update一个字段,整个表都会被锁起来,而别的进程,就算是读进程都无法操作直到写操作完成。另外,MyISAM对于SELECT COUNT(*) 统计 这类的计算是超快无比的。

  InnoDB的趋势会是一个非常复杂的存储引擎,对于一些小的应用,它会比MyISAM还慢。他是它支持“行锁”,于是在写操作比较多的时候,会更优秀。并且,他还支持更多的高级应用,比如:事务。

游标 cursor (跟循环有关) 

注意:性能不高!对每一行数据,分门别类的要进行计算的时候,才会使用!
  1、声明游标
  2、获取A表中的数据
    my_cursor select id ,num from A
  3、循环操作!for row_id,row_num in my_cursor: (不智能,不知道什么时候循环结束)
    #检测循环时候还有数据,如果没有数据就退出!
      insert into B(num) values (row_id+row_num)
  4、要想使用变量得先声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#代码举例
delimiter //
create  procedure  p6()
begin
     #声明变量
     declare  row_id  int -- 自定义变量1 
     declare  row_num  int -- 自定义变量2
     declare  done  INT  DEFAULT  FALSE ;
     declare  temp  int ;
     
     #创建游标
     declare  my_cursor  CURSOR  FOR  select  id,num  from  A;  -- 声明游标类型
     declare  CONTINUE  HANDLER  FOR  NOT  FOUND  SET  done =  TRUE -- 游标内部 没有值 done设置为True
     
     #开始操作
     open  my_cursor;  -- 打开游标
         xxoo: LOOP  语法:循环名:LOOP 开始循环
             fetch  my_cursor  into  row_id,row_num;
             if done  then
                 leave xxoo;
             END  IF;
             set  temp  = row_id + row_num;
             insert  into  B(number)  values ( temp );
         end  loop xxoo;
     close  my_cursor;  -- 关闭游标
 
end   //
delimter ;

动态执行SQL(防SQL注入)

伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
delimiter //
create  procedure  p7(
     in  tpl  varchar (255), # 接收一大堆的字符串
     in  arg  int
)
begin
     1. 预检测某个东西 SQL语句合法性  做防sql注入的问题
     2. SQL =格式化 tpl + arg 把传入的两个参数进行字符串格式化
     3. 执行SQL语句      -----> 拿取结果集
     
     set  @xo = arg;
     PREPARE  xxx(变量,随便起名字)  FROM  tpl ( 'select * from student where sid > ?' );
     EXECUTE  xxx USING @xo;    -- 注意:格式化的时候,传入的值必须是session级别的变量
     DEALLOCATE  prepare  xxx;  -- 执行格式化完成的SQL语句
end   //
delimter ;
call p7( "select * from tb where id > ?" ,9)  # ?表示占位符
1
2
3
4
5
6
7
8
9
10
11
12
13
======> 示例 <======
 
delimiter \\
CREATE  PROCEDURE  p8 (
     in  nid  int
)
BEGIN
     set  @nid = nid;
     PREPARE  prod  FROM  'select * from student where sid > ?' ;
     EXECUTE  prod USING @nid;
     DEALLOCATE  prepare  prod;
END \\
delimiter ;

数据库相关操作:
  1. SQL语句 ***** 优先使用 (要求速度!)
    - select xx() from xx ; 
  2.先查找内置函数,有就用! 利用MySQL内部提供的功能 (性能要求不高!)

索引

  索引是表的目录,在查找内容之前可以先在目录中查找索引位置,以此快速定位查询数据。对于索引,会保存在额外的文件中。

作用:
  - 约束
  - 加速查找
索引分类:
  - 主键索引:加速查找 + 不能为空 + 不能重复
  - 普通索引:加速查找
  - 唯一索引:加速查找 + 不能重复
  - 联合索引(多列):
    - 联合主键索引
    - 联合唯一索引
    - 联合普通索引

1、加速查找:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
快:
     select  from  tb  where  name = 'asdf'
     select  from  tb  where  id=999
假设:
     id   name   email
     ...
     ...
     ..
     
     无索引:对整个表从前到后依次查找
     
     索引:
             id      创建额外文件(某种格式存储)
             name     创建额外文件(某种格式存储)
             email   创建额外文件(某种格式存储)   create  index  ix_name  on  userinfo3(email);
         name   email 创建额外文件(某种格式存储)

索引种类(某种格式存储):
  hash索引: (存储是对表中的数据进行存储,无序)
    单值速度快
    范围速度慢 对于连续型的或是有范围的数据会慢,原因是hash表内存储的数据与原表中的数据不对称
  btree索引: 
    二叉树 索引 金字塔结构,从顶到底查找,左支比当前数小,右支比当前数大
  ========》 结果:快 《========

建立索引:

必须注意的三点
  - a. 额外的文件保存特殊的数据结构 (创建索引会重新创建一个文件,以保存对应的关系)
  - b. 查询快;但是执行 插入 更新 删除 操作时慢
  - c. 命中索引 (利用创建的索引进行查询,建立了不使用就是浪费)

1
2
select  from  userinfo3  where  email= 'aaa8888@163.com' ;
select  from  userinfo3  where  email  like  'new%' ; 慢 (模糊匹配,索引没用,还是会在原数据中一个一个去找)

主键索引:
  主键有两个功能:加速查询 和 唯一约束

普通索引:

1
2
create  index  索引名称  on  表名(列名,)
drop  index  索引名称  on  表名

唯一索引:

1
2
create  unique  index  索引名称  on  表名(列名)
drop  unique  index  索引名称  on  表名

组合索引:(最左前缀匹配)
  组合索引是将n个列组合成一个索引。其应用场景为:频繁的同时使用n列来进行查询
  遵循:最左前缀匹配规则,跟索引顺序有关,条件中第一个判断必须是建立组合索引的第一个值。

1
2
create  unique  index  索引名称  on  表名(列名1,列名2)
drop  unique  index  索引名称  on  表名
例:
- create index ix_name_email on test(name,email,)
- 最左前缀匹配
        select  * from test where name='alex666'; 会
        select  * from test where name='alex666' and email='alex666@163.com'; 会
        select  * from test where email='alex666@163.com'; 不会
        
示例

组合索引效率 > 索引合并 (具体还是以使用环境决定)

1
2
3
4
5
6
7
8
9
10
11
组合索引 (当查询的信息需要多个条件时)
     - ( name ,email,)
         select  from  test  where  name = 'aaa666'  and  email= 'aaa666@163.com' ; 快
         select  from  test  where  name = 'aaa666' ;
 
索引合并:(平常查询就用一个条件判断,多个条件不常用的情况)
     name
     - email
         select  from  test  where  name = 'aaa666' ; 快
         select  from  test  where  email= 'aaa666@163.com' ; 快
         select  from  test  where  name = 'aaa666'  and  email= 'aaa666@163.com' ; 相对快 

名词:虚拟存在的索引
覆盖索引:
  - 直接在索引文件中获取数据 (不是真实的索引)。select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖

1
例: select  email  from  test  where  email= "aaa2566666@163.com"

索引合并:- 把多个单列索引合并使用

1
例: select  email  from  test  where  email= "aaa2566666@163.com"  and  tid=2222222

文本索引:对整个数据表做成索引,不常用到,一般是用第三方软件去调用

注意:

  由于索引是专门用于加速搜索而生,所以加上索引之后,查询效率会快到飞起来。 
  数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。

2、为频繁查找的列创建索引 但是有些语法不会对索引加速

若想快速查询,我们的操作是这样的:
  - 创建索引
  - 命中索引 *****
  大数据量下注意,小数据没事!
但是,以下方式不会命中索引:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
like  '%xx'  模糊查找
     select  from  test  where  email  like  'aaa%' ;
     可用第三方工具去加速!
     
- 使用函数 取反 倒序
     select  from  test  where  reverse(email) =  'aaa235555@163.com' ;
     若想翻转查找,就在python中先把要查询的数据反转,再去和数据库内容匹配          
or 
     索引  or  非索引 就无法命中索引操作
     select  from  test  where  tid = 1  or  name  'aaa235555@163.com' ;
             
     特别的:当 or 条件中有未建立索引的列才失效,以下会走索引
 
             select  from  test  where  tid = 1  or  name  'aaa2666666'  and  email =  'aaa235555@163.com'  #会忽略非索引
             
             
- 查找条件,填写的数据类型不一致
     如果列是字符串类型,传入条件是必须用引号引起来,若是写成数字类型,这里边就涉及转码的过程,肯定会拖慢查询速度
     select  from  test  where  email = 999;
     
- !=  不等于 说白了就是取反
     select  from  test  where  email !=  'aaa'
     
     特别的:如果是主键,则还是会走索引
         select  from  test  where  tid != 123
 
- > 大于
     select  from  test  where  email >  'aaa1111111@163.com'
         
     特别的:如果是主键或索引是整数类型,则还是会走索引
         select  from  test  where  tid > 123
         select  from  test  where  num > 123
             
order  by  排序
     
     注意:当根据索引排序时候,选择的映射(要显示的列)如果不是索引,则不走索引
     select  name  from  test  order  by  email  desc ;
     
     特别的:如果对主键排序,则还是走索引:
         select  from  test  order  by  nid  desc ;
  
- 组合索引最左前缀
     如果组合索引为:( name ,email)
     name  and  email        -- 使用索引
     name                  -- 使用索引
     email                 -- 不使用索引

3、判断时间  

  explain + 查询SQL - 用于显示SQL执行信息参数,根据参考信息可以进行SQL优化

MySQL有执行计划:在真正执行操作之前,先让mysql预估执行操作(一般正确) 看看费时和type类型!好做判断!

1
2
3
4
5
语法:explain SQL语句     SQL 预估操作时间(仅作参考)
 
type类型: all  index  < range < index_merge < ref_or_null < ref < eq_ref < system/const
         all  是全局扫描
         ref 是索引扫描
1
2
3
4
5
6
7
8
9
10
11
#操作举例:
#搜索 id,email   
     慢:
         select  from  test  where  name = 'aaa2666666' 
         explain  select  from  test  where  name = 'aaa2666666'
         type:  ALL (全表扫描)
             select  from  test limit 1;
             #limit  分页获取是个例外,此种操作获取前面的数据会很快(因为操作的数据少啊),若起始是查找后边好几百万的数据行,照样飞不起来!
     快:
         select  from  test  where  email= 'aaa2666666'
         type: const(走索引)

4、DBA做的那些事儿

慢日志
  - 执行时间 > 10
  - 未命中索引
  - 日志文件路径

配置:(修改配置文件之前,一定要注意先备份!要不然就得跑路!!!)

- 程序执行暂存在内存中,同时配置信息也在!

- 查看当前配置信息:(内存内的变量)

1
2
show variables  like  '%query%'  #查看有 query 的变量 (主要是看配置信息,文件路径)
show variables  like  '%queries%'  #查看有 queries 的变量(主要是看索引)

- 修改当前配置:

1
2
3
4
5
set  global  变量名 = 值 
set  slow_query_log =  ON       开启慢日志记录
set  slow_query_log_file =  D:\mysql\setup\mysql-5.7.18-winx64\data\ZYJ-PC-slow.log   日志文件 默认在data目录中
set  long_query_time = 2      时间限制,超过此时间,则记录
set  log_queries_not_using_indexes =  ON     为使用索引的搜索记录

- 配置文件 写好配置文件,然后再开启数据库的时候一起执行生效,这样就省的在每次开启之后,再去配置!

1
2
3
4
5
6
7
8
9
开启执行:    mysqld  --defaults-file='配置文件的绝对路径+配置文件名'
 
创建配置文件    --->随意
 
配置文件内容:
     slow_query_log =  ON       开启慢日志记录
     slow_query_log_file =  D:\mysql\setup\mysql-5.7.18-winx64\data\ZYJ-PC-slow.log   日志文件 默认在data目录中
     long_query_time = 2      时间限制,超过此时间,则记录
     log_queries_not_using_indexes =  ON     为使用索引的搜索记录

注意:修改配置文件之后,需要重启服务生效(修改只是修改在硬盘内的文件,内容内的文件没有修改!)

5、******分页*******

  从数据库中取少量数据,那速度应该还可以,但是如果太庞大或是靠后的话,再去查找就会变慢。所以针对这种情况,我们给出了以下几个方法。

a. 限制页数,只能查看多少页

1
select  from  test limit 20,10;

b. 三种方法

  - 直接不让看

  - 索引表中扫:(覆盖索引)

1
2
3
4
SELECT  FROM  test
   WHERE  tid  in
    ( SELECT  N.tid  FROM
       ( SELECT  FROM  test LIMIT 2900000,10)  AS  N)

  - 方案:相对查找
    主要是 ------> 记录当前页最大或最小ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1. 页面只有上一页,下一页
     # max_id
     # min_id
     
     下一页:tid > max_id
         
         select  from  test  where  tid > 2900000 limit 10;
     
     上一页:tid < min_id
         
         SELECT  FROM
             ( select  from  test  where  tid < 2899991  ORDER  BY  tid  DESC  limit 10)  AS  N
                 ORDER  BY  N.tid  ASC ;
 
2. 跳页 上一页 192 193  [196]  197  198  199 下一页
     
     SELECT  FROM
         ( SELECT  FROM
             ( SELECT  FROM  test  WHERE  tid > 2800000 LIMIT 40)  AS  N
                 ORDER  BY  N.tid  DESC  LIMIT 10)  AS  ORDER  BY  S.tid  ASC

c. *****为什么不用 between and *****:
  最致命的原因:若id不连续,无法直接使用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=pymysql.cursors.DictCursor)
# 执行存储过程
cursor.callproc('p1', args=(1, 22, 3, 4))
# 获取执行完存储的参数
cursor.execute("select @_p1_0,@_p1_1,@_p1_2,@_p1_3")
result = cursor.fetchall()

conn.commit()
cursor.close()
conn.close()


print(result)
pymysql执行存储过程

 

转载于:https://www.cnblogs.com/SHENGXIN/p/7633269.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值