zoukankan      html  css  js  c++  java
  • 〖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:mysqlsetupmysql-5.7.18-winx64dataYJ-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:mysqlsetupmysql-5.7.18-winx64dataYJ-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执行存储过程
  • 相关阅读:
    水晶苍蝇拍:从“航空母舰”看企业竞争优势分析 (2010-05-11 11:48:38)
    水晶苍蝇拍:为何设定了安全边际后还吃大跌?
    水晶苍蝇拍:“低风险,高不确定性”的启示 (2010-04-24 22:02:13)
    水晶苍蝇拍:我这样看投资的安全性 (2009-08-27 20:08:53)
    水晶苍蝇拍:不同企业的估值差告诉我们什么? (2010-04-21 20:56:19)
    水晶苍蝇拍:估值,像雾像雨又像风 (2010-03-15 10:44:16)
    水晶苍蝇拍:长持的简单逻辑 (2009-05-25 18:08:43)
    Android中RelativeLayout各个属性的含义
    有道词典 Andriod 版本数据格式分析
    电驴提示“该内容尚未提供权利证明,无法提供下载”之解决办法详解
  • 原文地址:https://www.cnblogs.com/SHENGXIN/p/7633269.html
Copyright © 2011-2022 走看看