环境:phoenix 5.0 hbase2.0
连接上phoenix,建一个测试表:
create table test12(email varchar not null,id integer not null,name varchar not null,age integer,aihao varchar CONSTRAINT PK PRIMARY KEY (EMAIL,id,name));
这是3个字段组成的联合主键。
刚接触时,由于查询的条件较多。我曾想着把所有字段都设置成主键。那不是全部搞定了,哈哈哈。(别做梦,醒一醒,年轻人)
显然将所有字段都设计成,主键是不合理的。
我认为phoenix 主键的目的有两点:
1、与关系型数据库一样,唯一标识数据。
或许会用到这种语句:
UPSERT INTO TEST(ID, MY_COL) VALUES(123, 0) ON DUPLICATE KEY IGNORE;
2、作为查询的条件。
Hbase 的 rowKey 就是快。
开了个小差,回到正题:
测试表联合主键的先后顺序是(EMAIL,id,name)
那么如下SQL,有区别吗?
select * from test12 where email='a' and id=1;
select * from test12 where id=1 and email='a';
看一下执行计划
explain select * from test12 where email='a' and id=1;
explain select * from test12 where id=1 and email='a';
两个结果相同:
虽然会自动优化成相同的顺序,建议写条件时,还是按照顺序来写SQL。
其实还有一种情况,我遇到了,特别记录:
test3与 test13表:
这两张表字段全部相同,只是主键的顺序不同,我用来做对比的。
与之关联的表是test4:
问:
test3 与 test4 inner join
test13 与 test4 inner join
test3、test13 的条件也都相同,结果会不同吗?
先看test3的SQL 与 执行计划:
SELECT T1.LOGIN_DATE,T1.COUNTRY,T1.IP,T1.BROWSER,T1.USER_NAME,T1.GENDER,T1.EMAIL,T2.TIME_SPEND,T2.CAM_SITE,T2.TOKEN_EARNED,T2.REVENUE,T2.TIPS_SENT,T2.TOY FROM TEST4 T1 INNER JOIN (SELECT SEQ_ID,SHOW_DATE,EMAIL,TIME_SPEND,CAM_SITE,TOKEN_EARNED,REVENUE,TIPS_SENT,TOY FROM TEST3 WHERE SEQ_ID>=45665 AND SHOW_DATE='2018-11-13' ORDER BY SEQ_ID LIMIT 20) T2 ON (T1.LOGIN_DATE = T2.SHOW_DATE AND T1.EMAIL = T2.EMAIL)
WHERE T1.COUNTRY='China' AND T1.USER_NAME='wjc';
再看test13 的SQL 与 执行计划
SELECT T1.LOGIN_DATE,T1.COUNTRY,T1.IP,T1.BROWSER,T1.USER_NAME,T1.GENDER,T1.EMAIL,T2.TIME_SPEND,T2.CAM_SITE,T2.TOKEN_EARNED,T2.REVENUE,T2.TIPS_SENT,T2.TOY FROM TEST4 T1 INNER JOIN (SELECT SEQ_ID,SHOW_DATE,EMAIL,TIME_SPEND,CAM_SITE,TOKEN_EARNED,REVENUE,TIPS_SENT,TOY FROM TEST13 WHERE SEQ_ID>=45665 AND SHOW_DATE='2018-11-13' ORDER BY SEQ_ID LIMIT 20) T2 ON (T1.LOGIN_DATE = T2.SHOW_DATE AND T1.EMAIL = T2.EMAIL)
WHERE T1.COUNTRY='China' AND T1.USER_NAME='wjc';
细心的你看出不同了吗?哈哈哈,明显test13 与 test4 inner join更加合适。
结论:第一个主键不适合,序列号等,唯一标识的列。
让我们继续:
再看一下,这两个有区别吗?
select * from test12 where id=1;
select * from test12 where email='a';
执行计划:
条件为id的是全表扫描,而email是范围扫描。效率可想而知。
这种情况也是会进行范围扫描,但name条件走的是过滤筛选。
select * from test12 where email='a' and name='b';
结论:
如果有相关的页面、或者业务逻辑。
那么设计联合主键时,第一个主键,建议是必填的、使用频率最高的、值存在重复的。
关于提高查询效率,还有二级索引可以使用。