老哥们,我感觉我写的代码像 shi 一样。。求指点

2020-11-13 22:45:24 +08:00
 uselessVisitor

故事是这样子的。。。

领导让我制定个代码规范(小部门刚成立),然后看了阿里的规约,看到他们不推荐使用三个 left join 以上,心血来潮想测一下 left join 和在 java 中拼哪个快。

由于实力不行,模拟了 200000 条数据,当一次左连接并且加上索引时,很快啊,所有数据大概 200ms,然后我用 java 拼接,算了好久也没出结果。。现在我怀疑是我写的两个 for 复杂度太高了,请大佬们帮忙看一下我的 shi 一样的代码。。

//service 层拼
public Page<PersonInfoDTO> getPersonByJava() {
        long startTime = System.currentTimeMillis();
        IPage<PersonDO> personPage = personMapper.selectPage(new Page<>(),null);
        IPage<AddressDO> addressPage = addressMapper.selectPage(new Page<>(),null);
        //todo 获取 person 信息
        List<PersonDO> personDOList = personPage.getRecords();
        List<PersonInfoDTO> personInfoDTOList = new ArrayList<>();
       //todo 获取所有 address 信息
        List<AddressDO> addressDOList = addressPage.getRecords();
        int personSize = personDOList.size();
        int addressSize = addressDOList.size();
        for (int i = 0; i < personSize ; i++) {
            PersonDO personDO = personDOList.get(i);
            PersonInfoDTO personInfoDTO = new PersonInfoDTO();
            personInfoDTO.setName(personDO.getName());
            personInfoDTO.setSex(personDO.getSex());
            personInfoDTO.setId(personDO.getId());
            for (int j = 0; j < addressSize; j++) {
                AddressDO addressDO = addressDOList.get(j);
                if (addressDO.getName().equals(personInfoDTO.getName())){
                    personInfoDTO.setAddress(addressDO.getAddress());
                    personInfoDTOList.add(personInfoDTO);
                }
            }
        }
        Page<PersonInfoDTO> personInfoDTOPage = new Page<>();
        personInfoDTOPage.setRecords(personInfoDTOList);
        long endTime = System.currentTimeMillis();
        long usedTime  = endTime - startTime;
        System.out.println(usedTime);
        return personInfoDTOPage;
    }
 <!--name 加了索引-->
 <select id="getPersonByJoin" resultType="com.hpy.convertfoodemo.convert.entity.DTO.PersonInfoDTO">
        select t1.id,
               t1.name,
               t1.sex,
               t2.address
        from test.person t1
        left join test.address t2 on t1.name = t2.name
 </select>
3204 次点击
所在节点    Java
14 条回复
taogen
2020-11-13 23:32:18 +08:00
1. 代码有个错误,personInfoDTOList.add(personInfoDTO); 把这行放到第一层 for 循环最后一行而不是第二层 for 循环。修改后再试试时间吧。
2. 数据库 join 也和两层 for 循环类似,数据库可以有索引(索引效率 n^2 => nlogn ),Java 也可以构建类似索引,如 hashmap 。
3. 建议 Java 中构建索引(把第二层 for 循环用 addressMap.get(person.getAddress()) 替代,再试试时间效率。
taogen
2020-11-13 23:33:21 +08:00
代码错误 2:
if (addressDO.getName().equals(personInfoDTO.getName()))
to
if (addressDO.getName().equals(personInfoDTO.getAddress()))
taogen
2020-11-13 23:47:34 +08:00
另外,测试 SQL 执行时间。SQL 应该直接在数据库中执行,不要用 JDBC 。
xuanbg
2020-11-14 08:04:53 +08:00
所谓屎味代码,归纳下来就是这几种情况:
1 、多余,绕来绕去不知所云的无效代码。解决办法:理清业务逻辑,干掉重写。
2 、逻辑不完备,一旦出现特殊情况就会出 bug 。解决办法:多分析,然后进行归纳,使归纳后的逻辑能覆盖所有的可能性。
3 、低效,使用了不合适的方法处理数据。解决办法:不要因循守旧,也不要人云亦云。扩展视野,多尝试新技术新思路新方法。
jzphx
2020-11-14 08:50:51 +08:00
有时候觉得自己写出了完美的业务代码,多一个字符都破坏美感,在产品刀架脖子的情况下不得不 if else
hbolive
2020-11-14 10:09:40 +08:00
@jzphx 这种情况很常见
HolmLoh
2020-11-14 10:50:19 +08:00
@jzphx #5
经常碰到这种情况...我的做法是如果后续会拓展很多分支我就会开始翻设计模式
noparking188
2020-11-14 10:59:12 +08:00
我每天工作都糊 💩 就很难受,祖传💩 ⛰ 愈发硕大,今天看昨天的代码很糟糕,明天看今天的代码也很糟糕,想去重写下需求太多又没时间,需求一波未完一波又起,赶着你糊 💩
AEDaydreamer
2020-11-14 11:32:32 +08:00
@noparking188 太精辟了,第二天 review 一下代码发现能优化的地方很多.可是新的需求又来了,真的没时间改.
fangcan
2020-11-14 13:23:50 +08:00
你们重构完不需要测试部再测下么?还是都是自己测试吗
uselessVisitor
2020-11-14 13:54:34 +08:00
@taogen 感谢
darklowly
2020-11-14 14:41:27 +08:00
1 好好写注释,注释的格式是 // 后需要空格

2 好好排版,把代码分成逻辑上的段

3 好好取名字 getPersonByJava,这个名字看起来是单数,正常情况下应该是 listUsers

4 不熟悉 java 不知道 personMapper.selectPage 是干嘛的,选择某一页?

5 分解为两个函数,可能更快,伪代码

UserDTO getUserByID(string id) {
user = getUserRecord(id)
addr = getAddrRecord(id)
return buildUserDTO(user, addr)
}

Page<UserDTO> listUsers() {
// 分页查询用户 ID,具体的看你框架的语法
ids = queryUserIDs()

usersDTO = new ArrayListXXXXXXXXXXXX()
for (id := range ids) {
user = getUserByID(id)
usersDTO.add(user)
}

usersDTO
}
darklowly
2020-11-14 14:42:43 +08:00
1 好好写注释,注释的格式是 // 后需要空格

2 好好排版,把代码分成逻辑上的段

3 好好取名字 getPersonByJava,这个名字看起来是单数,正常情况下应该是 listUsers

4 不熟悉 java 不知道 personMapper.selectPage 是干嘛的,选择某一页?

5 分解为两个函数,可能更快,伪代码

```
UserDTO getUserByID(string id) {
user = getUserRecord(id)
addr = getAddrRecord(id)
return buildUserDTO(user, addr)
}

Page<UserDTO> listUsers() {
// 分页查询用户 ID,具体的看你框架的语法
ids = queryUserIDs()

usersDTO = new ArrayListXXXXXXXXXXXX()
for (id := range ids) {
user = getUserByID(id)
usersDTO.add(user)
}

usersDTO
}
```
darklowly
2020-11-14 14:46:18 +08:00
不知道怎么支持 markdown,将就看吧。

还有一点,你的代码也是密密麻麻的,不好看。函数内部,不同的逻辑区,需要分段,段之间用一个空行隔开。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/725039

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX