-
逆元+前缀和+前缀乘+二分+贪心
2018-10-04 11:06:31前言:一维 即一条线段的长度,二维 即x*y,三维 即x*y*z, 四维 即x*y*z*h, 五维。。。n维 然后题目给你一个数x 把这个数拆成x= ai + aj +...+ak (两两不相等) 然后输出这些数累乘的结果 再模一个数 要求...http://acm.hdu.edu.cn/showproblem.php?pid=5976
题意:
前言:一维 即一条线段的长度,二维 即x*y,三维 即x*y*z, 四维 即x*y*z*h, 五维。。。n维
然后题目给你一个数x 把这个数拆成x= ai + aj +...+ak (两两不相等)
然后输出这些数累乘的结果 再模一个数 要求结果最大
结论1:贪心策略 --》要想乘积最大:连续乘最好 2*3*4*5.。。。
我们要乘积最大,那么我们把n尽可能的拆分,如果题目不要求ai≠aj,那么我们将x拆分成什么最好呢?
显然拆成2和3(2为偶数,3为奇数,2x+3y可以表示大于1的所有正整数)是最好的,顺便提下3最多的时候最优,
为什么不是2,将,6拆成3个2乘积为8,而将6拆成3乘积为9,(不会证)注意:x最大10的九次方 测试发现最好那个数是45000 累乘结果会爆 所以只能保存取模结果
由于后面的结论推出 要除一些数 所以用到逆元
公式: inv[i] = (mod - mod / i) * inv[mod % i] % mod; //公式 递推求
或者快速幂
二分查找:找到第一个大于等于 利用负数来看比较好 lower_bound
如果找到小于等于 那个位置 接下来要补数 反而不好理解
收获:手动二分 如果那个数不存在的话 会找小于等于这个数的位置 如果结果加1 也做不到 lower那样大于等于 因为等于的情况就错了。所以以后尽量别手动,手动的话也最好是找一个确定存在的数。这样才不易错
#include<iostream> #include<cstring> #include<cmath> #include<string> #include<map> #include<vector> #include<set> #include<queue> #include<cstdio> #include<cstdlib> #include<algorithm> #include<functional> using namespace std; #define inf 0x3f3f3f3f #define pi acos(-1.0) #define LL long long #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 //#define mp make_pair #define pb push_back #define ULL unsigned LL #define mem(a, b) memset(a, b, sizeof(a)) #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) //#define fopen freopen("in.txt", "r", stdin);freopen("out.txt", "w", stout); const LL mod = 1e9 + 7; const int maxn = 45000; int sum[maxn]; LL mul[maxn], inv[maxn]; int qpow(int a, int b) { int res = 1; LL tmp = a;//注意tmp会爆 涉及乘法 while (b) { if (b & 1) res = res * tmp % mod; tmp = tmp * tmp % mod; b >>= 1; } return res; } void init() { sum[1] = 0, mul[1] = inv[1] = 1; for (int i = 2; i < maxn; ++i) { sum[i] = sum[i - 1] + i; mul[i] = mul[i - 1] * i % mod;//由于直接保存累乘结果会爆 所以保存取模结果 //inv[i] = (mod - mod / i) * inv[mod % i] % mod;//公式 递推求 inv[i] = qpow(i, mod - 2); } //cout << inv[2]; } int main() { /*int sum = 0; for (int i = 1; i <= 45000; ++i) { sum += i; } printf("%d", sum);*/ int t; scanf("%d", &t); init(); while (t--) { int x; scanf("%d", &x); if (x <= 4) { printf("%d\n", x); continue; } //找那么一个序列 2 + 3 + 4 + 。。。+ (最大数P - 一个负数a) int p = lower_bound(sum + 2, sum + maxn, x) - sum; //cout << p << endl; //int left = 2, right = maxn, mid;//【left, right) 左闭右开 //mid = (left + right) >> 1; //while (left + 1 < right) {//left + 1 == right 结束 // if (sum[mid] > x) // right = mid; // else // left = mid; // mid = (left + right) >> 1; //} //cout << mid << endl;//手动找的是小于(数不存在的话)等于x的位置 //现在求负数 因为加多了嘛 题目让我们求 这些数的积最大 同时这些数加起来要等于 x 现在加多了 要减走 即在累乘那里 除走 int a = x - sum[p]; //cout << a << endl; //可以发现 这个a的范围 -k, -(k - 1), - (k - 2), 。。。-2, -1, 0 //这个k就是(p - 1) /*结论:要想乘积最大:连续乘最好 2*3*4*5.。。。 我们要乘积最大,那么我们把n尽可能的拆分,如果题目不要求ai≠aj,那么我们将x拆分成什么最好呢? 显然拆成2和3(2为偶数,3为奇数,2x+3y可以表示大于1的所有正整数)是最好的,顺便提下3最多的时候最优, 为什么不是2,将,6拆成3个2乘积为8,而将6拆成3乘积为9,(不会证)*/ //现在看下怎么除去(时刻想着两个数相差越小 越优): a为0 不用去 //a为-1 把2去掉 此时又会多了一个1 加到p上 p变成p+1 即3*4*(5+1) //剩下的情况 都有一个对应的正数 去掉对应的正数 比如a=-5 2*3*4*5 //如果去掉2和3 乘积是20 去掉5的话是24 不太理解。。。这样就是最优 //现在有mul【】 要除去相应的数 再模----》逆元 LL ans; //可以发现比如 2*3*4*5=120 当x=13 即a==-1 根据策略 3*4*6=72 if (a == -1) ans = mul[p] * inv[2] % mod * inv[p] % mod * (p + 1) % mod; else if (a == 0) ans = mul[p]; else ans = mul[p] * inv[-a] % mod; printf("%lld\n", ans); } return 0; }
-
【MySQL】索引优化中的最左前缀原则和索引下推
2020-02-28 09:39:23三、最左前缀原则 最左前缀原则的定义 四、索引下推 五、小结 一、引入 在开始这篇文章之前,首先明确一个概念,聚集索引的B+树的每个节点就是一个索引页,索引页会根据先前规定好的度数来决定一个索引页放...目录
一、引入
在开始这篇文章之前,首先明确一个概念,聚集索引的B+树的每个节点就是一个索引页,索引页会根据先前规定好的度数来决定一个索引页放多少个索引值。
非叶子节点只有索引区(索引项),即只存放索引数据。
叶子节点有索引区和数据区(数据项),索引区存放的是索引数据,数据区的数据主键索引树和二级索引树有所不同:
- InnoDB表的主键索引树的叶子节点数据区存放的是整个表的数据。
- InnoDB表的二级索引树的叶子节点存放的是该结点索引对应的主键值。
很容易可以看出,B+数的结点会冗余地存储索引值,但是因为一个索引所占有的数据量很小,所以这种冗余影响不大。
下面我们来看一下这个问题:
在下面这个表 T 中,如果我执行 select * from T where k between 3 and 5,需要执行几次树的搜索操作,会扫描多少行?
下面是这个表的初始化语句。
mysql> create table T ( ID int primary key, k int NOT NULL DEFAULT 0, s varchar(16) NOT NULL DEFAULT '', index k(k)) engine=InnoDB; insert into T values(100,1,'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');
InnoDB 的索引组织结构 现在,我们一起来看看这条 SQL 查询语句的执行流程:
- 在 k 索引树上找到 k=3 的记录,取得 ID = 300;
- 再到 ID 索引树查到 ID=300 对应的 R3;
- 在 k 索引树取下一个值 k=5,取得 ID=500;
- 再回到 ID 索引树查到 ID=500 对应的 R4;
- 在 k 索引树取下一个值 k=6,不满足条件,循环结束。
因为B+树的叶子节点之间都按循序用指针连接在一起,所以k的索引树找到3的叶子节点之后直接根据叶子节点的后继指针到5结点就行了,依次同理,什么时候结点的索引值k不符合查询条件中的范围要求了就结束查询。
在这个过程中,回到主键索引树搜索的过程,我们称为回表。可以看到,这个查询过程读了 k 索引树的 3 条记录(步骤 1、3 和 5),回表了两次(步骤 2 和 4)。
在这个例子中,由于查询结果所需要的数据只在主键索引上有,所以不得不回表。那么,有没有可能经过索引优化,避免回表过程呢?这里就引入了覆盖索引的概念。
二、覆盖索引
如果执行的语句是 select ID from T where k between 3 and 5,这时只需要查 ID 的值,而 ID 的值已经在 k 索引树上了(辅助索引树的结点数据区存的是其对应的主键值),因此可以直接提供查询结果,不需要回表。也就是说,在这个查询里面,索引 k 已经“覆盖了”我们的查询需求,我们称为覆盖索引。
由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。
需要注意的是,在引擎内部使用覆盖索引在索引 k 上其实读了三个记录,R3~R5(对应的索引 k 上的记录项),但是对于 MySQL 的 Server 层来说,它就是找引擎拿到了两条记录,因此 MySQL 认为扫描行数是 2。
基于上面覆盖索引的说明,我们来讨论一个问题:在一个市民信息表上,是否有必要将身份证号和名字建立联合索引(创建联合索引就是创建覆盖索引的一种方式)?
假设这个市民表的定义是这样的:
CREATE TABLE `tuser` ( `id` int(11) NOT NULL, `id_card` varchar(32) DEFAULT NULL, `name` varchar(32) DEFAULT NULL, `age` int(11) DEFAULT NULL, `ismale` tinyint(1) DEFAULT NULL, PRIMARY KEY (`id`), -- 这个表的主键是单独建了一个id,不是用的身份证号,因为身份证号太长了,用它作为主键太占空间 KEY `id_card` (`id_card`), KEY `name_age` (`name`,`age`) ) ENGINE=InnoDB
我们知道,身份证号是市民的唯一标识。也就是说,如果有根据身份证号查询市民信息的需求,我们只要在身份证号字段上建立索引就够了(这样只需要先在身份证号索引树找到相应身份证号对应的主键ID,然后再从主键索引树根据查找到了主键ID找到相应的居民信息,只需要对B+数做两次查询)。而再建立一个(身份证号、姓名)的联合索引(这样建索引只需要在该索引上查询一次,就能在对应的索引项找找到所需要的数据,就不需要再回表查询主键索引树了),是不是浪费空间(因为每建立一个索引,都需要创建一个B+树并向里面存储相应的数据)?
如果现在有一个高频请求,要根据市民的身份证号查询他的姓名,这个联合索引就有意义了。它可以在这个高频请求上用到覆盖索引(将索引项中的索引字段覆盖要查询的字段,这就是覆盖索引),这样可以直接在辅助索引树中根据身份证号查询其名字了,因为虽然叶子节点的数据区依旧是存储的其辅助键对应的主键,但是在节点的索引区存储的是创建好的(身份证号+姓名)联合索引,可以直接从索引区取得需要的数据,不再需要回表查整行记录,减少语句的执行时间。
当然,索引字段的维护总是有代价的(详细见索引维护)。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这正是业务 DBA(数据库管理员),或者称为业务数据架构师的工作。
讲接下来的问题前首先讲一下联合索引的底层存储结构长什么样?联合索引的检索过程是什么样的呢?
联合索引中有多个字段,构建B+树的时候会将多个字段按照定义索引的顺序全部放到节点的索引区中,如上图所示。在进行索引树搜索比较索引的时候,是将多个字段从左向右比较(从上图来看就是从上到下比较)。
以上图为例查询过程有三种情况:
- 检索的数据与索引字段的第一个字段就不一样
- 检索的数据与索引字段的第一个字段一样
- 检索的数据与索引字段的前两个字段一样
- 情况一:要检索的where条件的数据是(10003,XXX,XXX),从树根开始检索发现比10002大,再与右面的10004比较发现比它小,所以直接就就进到右数据页中,不用再比较索引的后面两个字段了
- 情况二:要检索的where条件的数据是(10001,Assiatant),跟情况一过程一样,进入到比较完索引的第一个字段后直接进入到左数据页,发现查询数据的第一个字段与左数据页的三个结点的第一个字段都一样,那就接着比较第二个字段,发现和最左边的结点一样,那就直接是这个结点了,虽然索引区有三个字段,但是搜索字段只有两个,那么就不用管第三个字段了,直接就是这个字段。这也就是后面要讲的最左前缀原则,这个例子也就是最左前缀原则的执行过程。
- 情况三:要检索的where条件的数据是(10003,Staff,XXX),这种情况也就是按照第一种情况比较完,进入到右数据页,根据第二种情况比较完发现第二个字段也一样,而检索的数据还有一个字段就会接着去比较索引区的第三个字段
- 附加情况:如果要检索的where条件的数据是(10003),那么他就会按照情况一的过程去检索到右数据页,然后发现右数据页所有节点的第一个索引字段都是10003,因为搜索字段只有一个(10003),那么直接将右数据页的两个结点全部取得。这个也是最左前缀原则的应用
三、最左前缀原则
看到这里你一定有一个疑问,如果为每一种查询都设计一个索引,索引是不是太多了。如果我现在要按照市民的身份证号去查他的家庭地址呢?虽然这个查询需求在业务中出现的概率不高,但总不能让它走全表扫描吧?反过来说,单独为一个不频繁的请求创建一个(身份证号,地址)的索引又感觉有点浪费。应该怎么做呢?
这里,我先和你说结论吧。B+ 树这种索引结构,可以利用索引的“最左前缀”,来定位记录。
为了直观地说明这个概念,我们用(name,age)这个联合索引来分析。
(name,age)索引示意图 可以看到,索引项是按照索引定义里面出现的字段顺序排序的。
当你的逻辑需求是查到所有名字是“张三”的人时,可以快速定位到 ID4,然后向后遍历得到所有需要的结果。
如果你要查的是所有名字第一个字是“张”的人,你的 SQL 语句的条件是"where name like ‘张 %’"。这时,你也能够用上这个索引,查找到第一个符合条件的记录是 ID3,然后向后遍历,直到不满足条件为止。
以上就是最左前缀原则来加速检索的原理。所有的最左前缀原则的检索都是这个样子,如果有检索项个数小于索引项个数,比如只搜索“张三”,如果索引树中的索引项只有一个张三,那么直接取得这一个张三的节点。如果有多个张三的节点,则取多个节点返回(这个过程就是找到第一个张三节点之后因为索引树都是有序排列的,那么其他的张三节点也就顺序的存储在该节点的旁边,直接向右遍历取节点直到不符合条件为止),然后再一个个回表就行了。
最左前缀原则的定义:
可以看到,不只是索引的全部定义,只要满足最左前缀,就可以利用索引来加速检索。这个最左前缀可以是联合索引的最左 N 个字段,也可以是字符串索引的最左 M 个字符。也就是说你要查询的N个字段就包括在某个联合索引的最左N个字段内(不多不少正好就是这N个字段,顺序也得一致),那么你就不需要违者N个字段单独创捷一个索引,直接用现有的这个联合索引就可以,可以起到相同的效果。
像在最左边使用匹配符的这种,'%23',这种就不符合最左前缀原则,也就无法使用索引,这样的什么索引都是用不了,只能自己一个个去遍历,因为索引的比较都是从左到右开始,如果这种一开始就用一个%,比较就没有办法向下进行,所以也就无法使用索引了。
但是像上面这种情况在有些情况下是很不方便的
比如:在url表中存储url
我现在要找xyz后缀的域名,就需要这个样子'%com'查询,但是这样就无法使用索引会导致查询速度很慢
这种情况的解决办法就是倒着插入域名数据
moc.udiab.www
这样查询的时候就是'com%',这样就可以使用索引了,这也是一个在使用数据库时的小技巧。
基于上面对最左前缀索引的说明,我们来讨论一个问题:在建立联合索引的时候,如何安排索引内的字段顺序。
这里我们的评估标准是,索引的复用能力。因为可以支持最左前缀,所以当已经有了 (a,b) 这个联合索引后,一般就不需要单独在 a 上建立索引了。因此,第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。
所以现在你知道了,本节开头的问题里,我们要为高频请求创建 (身份证号,姓名)这个联合索引,而“根据身份证号查询地址”的需求并不是高频需求,我们没必要为其维护一个(身份证号,地址)的联合索引。而如果想提高根据身份证号查询地址的搜索速度,就得需要一个(身份证号)索引,否则MySQL就会遍历整个B+树来查询该内容。而这时我们的最左前缀原则就能派上用场,根据该原则直接就能用高频请求的(身份证号,姓名)联合索引来充当(身份证号)索引的功校,用这个索引支持“根据身份证号查询地址”的需求(通过该联合索引找到快速找到身份证号对应的主键ID,才从主键索引树中快速找到对应主键ID的叶子节点,也就找到了该ID的所有数据其中就包括地址)。
那么,如果既有联合查询,又有基于 a、b 字段各自的查询呢?查询条件里面只有 b 的语句,是无法使用 (a,b) 这个联合索引的,这就不符合最左前缀的原则了。这时候你不得不维护另外一个索引,也就是说你需要同时维护 (a,b)、(b) 这两个索引。
这时候,我们要考虑的原则就是空间了。比如上面这个市民表的情况,name 字段是比 age 字段大的 ,那我就建议你创建一个(name,age) 的联合索引和一个 (age) 的单字段索引。就不要建立(age,name)联合索引和(name)索引了,虽然效果是一样的,但是后者存储了两次name大字段,更占空间。
四、索引下推
上一段我们说到满足最左前缀原则的时候,最左前缀可以用于在索引中定位记录。这时,你可能要问,那些不符合最左前缀的部分,会怎么样呢?
我们还是以市民表的联合索引(name, age)为例。如果现在有一个需求:检索出表中“名字第一个字是张,而且年龄是 10 岁的所有男孩”。那么,SQL 语句是这么写的:
mysql> select * from tuser where name like '张%' and age=10 and ismale=1;
你已经知道了前缀索引规则,所以这个语句在搜索索引树的时候,只能用 “张”,找到第一个满足条件的记录 ID3。当然,这还不错,总比全表扫描要好。
然后呢?当然是判断其他条件是否满足。
在 MySQL 5.6 之前,只能从 ID3 开始一个个回表。到主键索引上找出数据行,再对比字段值。而 MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。
图1和图2,是这两个过程的执行流程图。
图 1 无索引下推执行流程 图 2 索引下推执行流程 在图 1 和 2 这两个图里面,每一个虚线箭头表示回表一次。
图 1 中,在 (name,age) 索引里面我特意去掉了 age 的值,这个过程 InnoDB 并不会去看 age 的值,只是按顺序把“name 第一个字是’张’”的记录一条条取出来回表。因此,需要回表 4 次。
图 2 跟图 1 的区别是,InnoDB 在 (name,age) 索引内部就判断了 age 是否等于 10,对于不等于 10 的记录,直接判断并跳过。在我们的这个例子中,只需要对 ID4、ID5 这两条记录回表取数据判断,就只需要回表 2 次。
五、小结
今天这篇文章,我和你继续讨论了数据库索引的概念,包括了覆盖索引、前缀索引、索引下推。你可以看到,在满足语句需求的情况下, 尽量少地访问资源是数据库设计的重要原则之一。我们在使用数据库的时候,尤其是在设计表结构时,也要以减少资源消耗作为目标
其他相关文章:【MySQL】MySQL的存储引擎和索引详解(聚集索引和非聚集索引)
【MySQL】InnoDB行格式、数据页结构以及索引底层原理分析
【MySQL】InnoDB存储引擎,MyISAM存储引擎,聚集索引,非聚集索引,主键索引,二级索引他们之间的关系梳理
【MySQL】InnoDB 的索引模型(B+树)
【MySQL】MySQL的锁与事务隔离级别详解
【MySQL】MySQL分库分表详解
【MySQL】主从复制实现原理详解参考资料:《MySQL实战45讲》林晓斌
-
索引的使用,最左前缀原则
2019-09-07 21:02:09第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。 第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。 第四,在使用分组和排序子句进行数据检索时,同样可以显著减少...创建索引可以大大提高系统的性能。
第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
也许会有人要问:增加索引有如此多的优点,为什么不对表中的每一个列创建一个索引呢?因为,增加索引也有许多不利的方面。
第一,创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
第二,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
索引是建立在数据库表中的某些列的上面。在创建索引的时候,应该考虑在哪些列上可以创建索引,在哪些列上不能创建索引。一般来说,应该在这些列上创建索引:在经常需要搜索的列上,可以加快搜索的速度;在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
同样,对于有些列不应该创建索引。一般来说,不应该创建索引的的这些列具有下列特点:
第一,对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
第二,对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。
我们先来看一下索引的分类,索引大致可按如下分类:
从数据结构角度
1、B+树索引(O(log(n))):关于B+树索引,可以参考 MySQL索引背后的数据结构及算法原理
2、hash索引:
a. 仅仅能满足"=",“IN"和”<=>"查询,不能使用范围查询
b. 其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引
c. 只有Memory存储引擎显示支持hash索引从物理存储角度
1、聚集索引(clustered index)
2、非聚集索引(non-clustered index)
从逻辑角度
1、普通索引或者单列索引
2、唯一索引
3、主键索引:主键索引是一种特殊的唯一索引,不允许有空值
4、多列索引(复合索引):复合索引指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用复合索引时遵循最左前缀集合
5、全文索引
在上文中,我们已经了解了数据结构及物理存储角度,今天我们主要从逻辑角度来看看索引:
1、普通索引:这是最基本的索引类型,而且它没有唯一性之类的限制。普通索引可以通过以下几种方式创建:
创建索引,例如CREATE INDEX <索引的名字> ON tablename (列的列表);
修改表,例如ALTER TABLE tablename ADD INDEX [索引的名字] (列的列表);
创建表的时候指定索引,例如CREATE TABLE tablename ( […], INDEX [索引的名字] (列的列表) );2、唯一索引:这种索引和前面的“普通索引”基本相同,但有一个区别:索引列的所有值都只能出现一次,即必须唯一。唯一性索引可以用以下几种方式创建:
创建索引,例如CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表);
修改表,例如ALTER TABLE tablename ADD UNIQUE [索引的名字] (列的列表);
创建表的时候指定索引,例如CREATE TABLE tablename ( […], UNIQUE [索引的名字] (列的列表) );3、主键索引
主键是一种唯一性索引,但它必须指定为“PRIMARY KEY”。如果你曾经用过AUTO_INCREMENT类型的列,你可能已经熟悉主键之类的概念了。主键一般在创建表的时候指定,例如“CREATE TABLE tablename ( […], PRIMARY KEY (列的列表) ); ”。但是,我们也可以通过修改表的方式加入主键,例如“ALTER TABLE tablename ADD PRIMARY KEY (列的列表); ”。每个表只能有一个主键。
4、复合索引(组合索引、多列索引)
为了形象地对比单列索引和组合索引,为表添加多个字段:
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, city VARCHAR(50) NOT NULL, age INT NOT NULL );
为了进一步榨取MySQL的效率,就要考虑建立组合索引。就是将 name, city, age建到一个索引里:ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age);
建表时,usernname长度为 16,这里用 10。这是因为一般情况下名字的长度不会超过10,这样会加速索引查询速度,还会减少索引文件的大小,提高INSERT的更新速度。
如果分别在 usernname,city,age上建立单列索引,让该表有3个单列索引,查询时和上述的组合索引效率也会大不一样,远远低于我们的组合索引。虽然此时有了三个索引,但MySQL只能用到其中的那个它认为似乎是最有效率的单列索引。
建立这样的组合索引,其实是相当于分别建立了下面三组组合MySQL数据库索引:
usernname,city,age usernname,city usernname 为什么没有 city,age这样的组合索引呢?这是因为MySQL组合索引“最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这三列的查询都会用到该组合索引,下面的几个SQL就会用到这个组合MySQL数据库索引:
SELECT * FROM mytable WHREE username=“admin” AND city=“郑州”
SELECT * FROM mytable WHREE username=“admin”
而下面几个则不会用到:
SELECT * FROM mytable WHREE age=20 AND city=“郑州” SELECT * FROM mytable WHREE city=“郑州”
关于最左前缀的问题,我们会在后面讨论到
5、全文索引
MySQL从3.23.23版开始支持全文索引和全文检索。在MySQL中,全文索引的索引类型为FULLTEXT。全文索引可以在VARCHAR或者 TEXT类型的列上创建。它可以通过CREATE TABLE命令创建,也可以通过ALTER TABLE或CREATE INDEX命令创建。对于大规模的数据集,通过ALTER TABLE(或者CREATE INDEX)命令创建全文索引要比把记录插入带有全文索引的空表更快。本文下面的讨论不再涉及全文索引,要了解更多信息,请参见mysql全文索引。
最左前缀原则
mysql建立多列索引(联合索引)有最左前缀的原则,即最左优先,如:如果有一个2列的索引(col1,col2),则已经对(col1)、(col1,col2)上建立了索引;
如果有一个3列索引(col1,col2,col3),则已经对(col1)、(col1,col2)、(col1,col2,col3)上建立了索引;1、b+树的数据项是复合的数据结构,比如(name,age,sex)的时候,b+树是按照从左到右的顺序来建立搜索树的,比如当(张三,20,F)这样的数据来检索的时候,b+树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据;但当(20,F)这样的没有name的数据来的时候,b+树就不知道第一步该查哪个节点,因为建立搜索树的时候name就是第一个比较因子,必须要先根据name来搜索才能知道下一步去哪里查询。
2、比如当(张三,F)这样的数据来检索时,b+树可以用name来指定搜索方向,但下一个字段age的缺失,所以只能把名字等于张三的数据都找到,然后再匹配性别是F的数据了, 这个是非常重要的性质,即索引的最左匹配特性。(这种情况无法用到联合索引)
关于最左前缀的使用,有下面两条说明:
最左前缀匹配原则,非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。
=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式
关于最左前缀的例子,请参考:https://www.kancloud.cn/kancloud/theory-of-mysql-index/41857什么时候索引会失效
如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因)。注意:要想使用or,又想让索引生效,只能将or条件中的每个列都加上索引
对于多列索引,不是使用的第一部分,则不会使用索引(即不符合最左前缀原则)
like查询是以%开头
如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
如果mysql估计使用全表扫描要比使用索引快,则不使用索引 -
四大内核与五大浏览器
2020-08-22 22:48:17文章目录四大内核与五大浏览器一.简介二.浏览器内核组成三.四大内核1.Trident2.Gecko3.Webkit4.Chromium/Blink5.Presto(淘汰)四.五大浏览器1.IE浏览器2.Opera浏览器3.Safari浏览器4.Firefox浏览器5.Chrome浏览器五....四大内核与五大浏览器
文章目录
一.简介
浏览器最重要的部分是浏览器的内核,浏览器内核是浏览器的核心,也称之为"渲染引擎",用来解释网页语法并渲染到页面上,浏览器内核决定了浏览器该如何显示网页内容以及页面的格式信息,不同的浏览器内核对网页的语法解释也不同,因此网页开发者需要在不同的内核的浏览器中测试网页渲染效果.
二.浏览器内核组成
浏览器内核可以分为两个部分:
(1) 渲染引擎
(2) JS引擎
内核负责取得网页的内容(
HTML
,XML
,图像等等),整理讯息(比如j加入CSS
),以及计算网页的显示方式,然后输出到显示器或打印机.浏览器内核的不同对于网页的语法解释也会有不同,所以渲染效果也不相同.所有网页浏览器,电子邮箱客户端,以及其它需要编辑,显示网络内容的应用程序都需要内核.
JS
引擎则是解析JavaScript
语言,执行JavaScript
语言来实现网页的动态效果.最开始渲染引擎和jS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎.
三.四大内核
内核种类很多,但常见的浏览器内核有四种:Trident,Gecko,Blink,Webkit
1.Trident
IE的内核,也就是国内双核浏览器的内核之一,此内核只能用于windows平台,且不是开源的.Trident内核一直延续到IE11,IE11的后继者Edge采用了新的内核EdgeHTML
2.Gecko
开源内核,后来被FireFox采用,最大的优势是跨平台,在Windows,Linux,MacOs等主要操作系统中使用
3.Webkit
开源内核,
Webkit
最先使用的其实是Safari
,苹果的浏览器,后来Chrome
将WebKit
内核推向高潮,曾经的Chrome
用的就是WebKit
PS:WebKit其实包括是渲染引擎WebCore(前身是KHTML),以及JS引擎JSCore
Safari浏览器内核:WebKit内核 KHTML=>WebKit(WebCore+JSCore)=>WebKit2
4.Chromium/Blink
开源内核,
Chromium
其实是WebKit
的一个分支,代码可读性,和编译速度得到提升,并且谷歌专门研发的自己的JS-V8引擎
,极大的提高了JS
的运算速度Blink
其实是WebKit
的分支,如同WebKit
是KHTML
的分支.Blink
内核是有Google
和Opera Software
共同研发,目前Chrome内核是Blink
Chromium内核=>WebKit内核=>Blink内核
5.Presto(淘汰)
Presto
是Opera Software
(欧朋软件)开发的浏览器引擎,它是世界上公认最快的渲染速度的引擎.后来Opera
放弃了Presto
加入谷歌的阵营,采用Chromium
,之后也采用Blink
四.五大浏览器
1.IE浏览器
IE是微软旗下浏览器,是目前国内用户量最多的浏览器
2.Opera浏览器
Opera是挪威欧朋软件公司旗下的浏览器.Opera之前使用的是Presto内核,后来使用Blink内核
3.Safari浏览器
Safari是苹果公司的浏览器,最早使用webkit内核的浏览器,也是现在苹果默认的浏览器
4.Firefox浏览器
Firefox是Mozilla公司旗下的浏览器,Firefox采用Gecko作为内核
5.Chrome浏览器
Chrome是Google旗下的浏览器,最开始采用的是Webkit作为浏览器内核,后来采用Webkit的分支Blink作为内核
五.浏览器前缀兼容写法
1.-ms-
一般使用Trident内核的,需要添加这个前缀,比如IE浏览器,或者使用IE内核的
2.-moz-
典型代表是火狐浏览器(Mozilla),使用Gecko内核的,也就是Firefox内核
3.-o-
早期的时候,使用Opera浏览器的,现在不需要了
4.-webkit-
典型的2个浏览器,Safari和谷歌浏览器等使用Webkit作为内核的
5.需要添加前缀的属性
属性 描述 @keyframes 规则 定义动画的规则 transition-property 移动和变换属性 transition-duration 移动和变换属性 transition-timing-function 移动和变换属性 transition-delay 移动和变换属性 animation-name 动画属性 animation-duration 动画属性 animation-timing-function 动画属性 animation-delay 动画属性 border-radius 圆角边框 box-shadow 阴影 backface-visibility 隐藏元素的背面,在元素旋转时,背面不可见可使用这属性 column属性 列属性 flex属性 弹性盒 perspective属性 3D元素 六.总结
浏览器 内核 描述 IE浏览器 Trident 俗称IE内核 Chrome浏览器 Webkit=>Blink 统称为Chromium内核或Chrome内核,以前是Webkit内核,现在是Blink内核 Firefox浏览器 Gecko 俗称Firefox内核 Opera Presto=>Webkit=>Blink 最初是自己的Presto内核,后来是Webkit,现在是Blink内核 360浏览器,猎豹浏览器 IE+Chrome双内核 双内核浏览器 搜狗,遨游,QQ Trident+Webkit Trident(兼容模式)+Webkit(高速模式) 百度,世界之窗 IE内核 Trident 2345浏览器内核 IE+Chrome 以前是IE内核,现在是IE+Chrome -
前缀、中缀、后缀表达式-java,中缀转后缀,逆波兰计算器实现
2020-05-05 19:01:19前缀表达式的计算机求值二、中缀表达式三、后缀表达式1. 后缀表达式的计算机求值四、中缀转后缀表达式五、逆波兰计算器 一、前缀表达式(波兰表达式) 前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前 举例... -
LeetCode - 1018 - 可被5整除的2进制前缀(binary-prefix-divisible-by-5)
2020-03-09 07:40:45一 目录 不折腾的前端,和咸鱼有什么区别目录一 目录二 前言三 解题及测试四 LeetCode Submit五 解题思路六 进一步思考二 前言 难度:简单涉及知识:数组题目地址:http... -
[转]OFDM中保护间隔和循环前缀抵抗ISI和ICI
2019-10-03 07:50:44主要参考文档:OFDM移动...一、符号间干扰ISI 与 信道间干扰ICI 的概念 二、保护间隔 减少 ISI 三、循环前缀 减少 ICI 四、保护间隔与循环前缀 加入后的OFDM系统框图 五、选择 保护间隔 的方法 ===============... -
在用前缀[rili]导入的标记库中未定义标记[ShowCalendar]。
2020-10-28 12:44:15<tr><th>星期日</th><th>星期一</th><th>星期二</th><th>星期三</th><th>星期四</th><th>星期五</th><th>星期六</th></tr> (int n = 0;n;n=n+7){ %> (int i =n;i;i++){ %> <td><%=day[i] %> %> %> ... -
OFDM中保护间隔与循环前缀抵抗ISI…
2013-08-31 22:05:02主要参考文档:OFDM移动通信技术原理...四、保护间隔与循环前缀 加入后的OFDM系统框图 五、选择 保护间隔 的方法 ====================================== 符号间干扰ISI 与 信道间干扰ICI 的概念 多径时延扩 -
【数据结构(C++实现)】:Trie_字典树_前缀树
2018-09-07 21:06:25目录 一、介绍 ...四、Trie结点的定义 五、Trie接口定义 六、插入字符串 七、搜索字符串 1.搜索前缀 2.搜索单词 3.时间复杂度 八、完整代码 一、介绍 Trie,又称字典树或前... -
OFDM中保护间隔与循环前缀抵抗ISI与ICI(转)
2014-06-29 14:37:00一、符号间干扰ISI 与 信道间干扰ICI 的概念二、保护间隔 减少 ISI三、循环前缀 减少 ICI四、保护间隔与循环前缀 加入后的OFDM系统框图五、选择 保护间隔 的方法 ====================================== 符号间... -
【Spring扩展点003】spring处理Import注解的过程(核心:四种情况)
2020-07-27 21:47:27文章目录一、前言二、Enable前缀的注解上面有@Import注解三、常见的四种Import注解用法列举四、Spring对于@Import注解的处理(全文重点)五、官方API文档中的疑问解答六、金手指六、小结 一、前言 文章概览 本章由以下... -
JSP-MyBatis(三)高级查询+分页+注解+延时+缓存+多对一
2020-02-12 23:01:07二、#和$的区别 三、使用注解的方式 1.配置映射 2.使用@Param的注解: 四、many2One 五、延时加载 六、N+1问题 七、一级缓存 一、高级查询+分页: 核心代码示意图 Notes: 1.动态SQL语句中<WHERE>... -
(三)HBase的Java代码开发
2019-08-28 09:15:20文章目录HBase的Java代码开发(一)创建表(二)删除表(三)向表中添加数据(四)删除数据(五)查询数据1.Get查询2.Scan查询3.RowFilter行键过滤器4.FamilyFilter列族过滤器5.QualifierFilter列过滤器6.ValueFilter值过滤器7... -
【链表第四篇】四链表删除最小值、双链表按访问次数排序
2020-10-10 22:49:04文章目录一、前言二、循环单链表每次循环删除一个最小的三、单链表每次循环删除一个最小的四、循环双链表每次循环删除一个最小的五、双链表每次循环删除一个最小的六、循环双链表记录访问次数,按访问次数排序七、双... -
详解grep(一)grep基础、语法格式、常用选项与退出状态码的案例解析
2019-01-13 21:44:09目录 一、GREP基础 1.1 grep的全称 1.2 grep语法格式 二、grep常用选项 2.1 长短选项的说明 ...2.3 控制匹配模式的选项 ...2.4 控制输出内容的选项 ...四、不同的搜索引擎(不同的grep程序) 五、sed、awk、gr... -
四、传统IDC部署网站
2019-09-18 06:36:58传统IDC部署网站一、rm命令二、环境变量PATH三、CP命令四、MV命令五、cat、more、less、head、tail六 文件或目录权限chmod七、所有者所属组chown八、umask一、rm命令 rm可以删除文件及非空目录rm -f 强制性删除而不... -
Opengl es2.0 学习笔记(四)shader语法 GLSL
2018-11-15 18:11:00文章目录一、变量二、基本类型三、结构体四、数组五、修饰符六、内置变量七、操作符八、数组访问九、构造函数十、成分选择十一、控制流十二、函数 一、变量 GLSL的变量命名方式与C语言类似。变量的名称可以使用字母... -
javascript初探(五)------ BOM
2021-03-06 14:01:04目录一、概述二、window对象三、navigator对象四、location对象五、history对象六、screen对象 一、概述 BOM:浏览器对象模型,提供了方法和属性,让开发者可以通过js对浏览器进行操作 包含:window对象、navigator... -
C/C++常见面试题(二)
2018-08-03 17:16:12二、define与const的区别 三、typedef的用法 四、define与typedef的区别 五、static在C/C++中的用法 六、指针函数与函数指针/指针数组与数组指针 七、前缀++i和后缀i++的区别 八、sizeof和strlen的区别 九、... -
第四届蓝桥杯C/C++ B组
2017-04-06 19:45:51这里写我会写的~ 第一题:高斯日记 4’ 第二题:马虎的算式 5’ ...第五题:前缀判断 5’ 第六题:三部排序 7’ 第七题:错误票据 4’ 第八题:翻硬币 10’ 第九题:带分数 16’ 第十题:连号区间数 29’ -
一个系列搞懂Mysql数据库5:根据MySQL索引原理进行分析与优化
2020-09-05 09:23:53Table of Contents 一:Mysql原理与慢查询 一个慢查询引发的思考 二:索引建立 三:浅析explain用法 ...五:最左前缀原理与相关优化 情况一:全列匹配。 情况二:最左前缀匹配。 情况三:查询条件用到了索引中列的精 -
2013第四届蓝桥杯C/C++ B组(省赛)试题汇总及试题详解
2019-05-28 20:46:29目录 第一题:高斯日记 ...第二题:马虎的算式 第三题:第39级台阶 第四题:黄金连分数 第五题:前缀判断 第六题:三部排序 第七题:错误票据 第八题:翻硬币 第九题:带分数 第十题:连号区间数 ... -
2013年第四届C/C++ A组蓝桥杯省赛真题
2020-12-20 20:43:08目录第一题: 高斯日记第二题:排它平方数第三题:振兴中华第四题:颠倒的价牌第五题:前缀判断第六题:逆波兰表达式第七题:错误票据第八题:买不到的数目第九题:剪格子第十题:大臣的旅费 第一题: 高斯日记 ... -
php判断一个url端口通不通
2021-03-05 15:40:15第一个参数需要注意,是目标的请求地址,这里有个小坑需要注意,就是目标地址前缀不能是http://,fsockopen不支持http://前缀的网址,第二个参数就是端口,第三个状态码,第四个错误信息,第五个超时时间,还不清楚的... -
2013年第四届C B组蓝桥杯省赛真题
2020-12-15 22:46:11目录第一题:高斯日记(4分)第二题:马虎的算式(5分)第三题:第39级台阶(8分)第四题:黄金连分数(12分)第五题:前缀判断(5分)第六题:三部排序(7分)第七题:错误票据(4分)第八题:翻硬币(10分)第九题... -
2020牛客多校第二场补题博客
2020-08-23 17:18:392020牛客多校第二场补题博客一、All with Pairs(A)二、Boundary(B)三、Cover the Tree(C)四、Fake Maxpooling(F)五、Greater and Greater(G) 一、All with Pairs(A) 题目链接:All with Pairs 题目大意... -
三、shell 条件测试实战实例
2020-05-18 12:37:13${#变量} 判断一个变量的长度是否为0例3:扩充,命令判断二、文件测试:三、数值测试:实例1:输入用户名并进行创建,测试该用户名是否为空实例2:如果磁盘根分区使用量超过90%就报警实例3:如果内存使用率超过60%就... -
PHP基础教程 是一个比较有价值的PHP新手教程!
2010-04-24 18:52:44可能你已经注意到,变量都有一个美元符号($)的前缀。所有变量都是局部变量,为了使得定义的函数中可以使用外部变量,使用global语句。而你要将该变量的作用范围限制在该函数之内,使用static语句。 $g_var = 1 ; /...