假设有个表store
内有字段product
和 texture
, 内容分别类似12|15|18,与61|22|29,第一组数字代表这个商店内的所有产品id,第二组数字代表所有材质的id。
产品和商圈数据库结构如下:(产品与材质都是store的属性,互不相关)
product:
id | product |
---|---|
1 | 手链 |
2 | 戒指 |
3 | 项链 |
texture:
id | texture |
---|---|
1 | 紫檀木 |
2 | 花梨木 |
以什么方式才能达到如下展示并且尽量高效呢?
商家名称:某某某
产品: 手链 戒指 项链
材质: 紫檀木 花梨木
我想了半天,给出了自认为效率比较低的办法:
由于MySQL返回的数组索引是递增的,如
[
0=>[id=>1,product=>'手链'],
1=>[id=>2,product=>'戒指'],
2=>[id=>3,product=>'项链'],
]
我对这个数组进行一个变换,将其变成以id为主键:
$product=> [
1=>'手链',
2=>'戒指',
3=>'项链'
]
然后将store的属性12|15|18 explode开,将每个数字作为key值,显示$product[$key]
但是总觉得这种效率好低,请问程序员朋友们有没有更好的办法?
或者说,有没有什么办法,从MySQL中取数据的时候,可以指定某一个字段作为数据的索引?将其直接以我转换后的形式返回?
1
alphonsez 2015-07-05 21:40:31 +08:00
这个效率不低啊。你query一次db比你iterate一次数组要慢好多。
|
2
rqrq 2015-07-05 22:08:25 +08:00
题本身就有问题,要缓存也不应该是这种形式,字段直接存带 id 和名字的 serialize 或者 json_encode 之后的字符串不就行了,表都不用查。
你可以再反问他,store 表数据量有多大?访问量有多大?几万数据小百万 pv 的话缓存都不需要做。 再,你的数组问题: 返回的 『0, 1, 2 数组』不是 mysql 直接生成的,而是通过 while 循环或者调用了 mysqli_fetch_all 组合而成的,你可以自己去控制,生成你想要的数组,减少一次循环,伪代码如下,可能缩进显示不出来,凑合看。 生成『0, 1, 2 数组』 $query = mysqli_query($this->link, $sql); if (function_exists('mysqli_fetch_all')) { return mysqli_fetch_all($query, MYSQLI_ASSOC); } else { $ret = $retlist = array(); while ($ret = mysqli_fetch_array($query, MYSQLI_ASSOC)) { $retlist[] = $ret; } return $retlist; } 生成你想要的『 1, 2, 3 数组』 $query = mysqli_query($this->link, $sql); $ret = $retlist = array(); while ($ret = mysqli_fetch_array($query, MYSQLI_ASSOC)) { $retlist[$ret['id']] = $ret['name']; } return $retlist; |
3
LaughingMeMe 2015-07-05 22:10:48 +08:00
@alphonsez not sure
|
4
LaughingMeMe 2015-07-05 22:12:06 +08:00
@rqrq nice
|
5
br00k 2015-07-05 22:15:58 +08:00
丢给客户端处理。split()
:) |
6
rming 2015-07-05 22:18:26 +08:00
怎么看起来像是前端的事,把 product,texture 和 两个table给前端,前端随便搞,爱咋显示咋显示,后端就是三个查询,都会走主键索引
|
7
rqrq 2015-07-05 22:20:51 +08:00 1
另外,考虑到『墨菲定律』,如果 store 表要放缓存的内容,不管缓存的是什么样的形式,都应该有两个单独的表来存放 store 跟 product 以及 texture 的对应关系,当 product 或者 texture 中的 item 名字有变化或者被删除时,要更新对应的缓存数据。
话说这种缓存真的很无聊,省几毫秒,反而带来很多麻烦,如果不是访问量特别大尽量少用。 |
8
dangyuluo OP @alphonsez 数据比较少的时候我觉得可以,但是如果product和texture有上千条,平白无故添加很多计算量。
|
10
Septembers 2015-07-05 23:41:47 +08:00 via Android
@dangyuluo 我觉得 单库单表规模没达到一亿行以上,还是不要讨论这个话题
|
11
Septembers 2015-07-05 23:44:42 +08:00 via Android
@dangyuluo 现代Java模板引擎性能最好的能达到1.5万次每秒
|
12
alphonsez 2015-07-06 00:33:45 +08:00
@dangyuluo
没多多少,从数据库度这些出来就是O(n)的,你只不过再for一遍而已。很快的。 别的不说,你从数据库取出来要过一遍,你最后显示的时候总要过一遍,中间有啥过滤操作还是要过一遍。多过一遍而已。 另外,product, texture真的会有数千条吗?如果有,你展示的时候怎么也给个分页吧不然谁看啊。 |
13
mhycy 2015-07-06 08:48:44 +08:00
@alphonsez product, texture两个是属性,属性有上千个可能值是很正常的。
说回来,这种建表模式总觉得该打。。。 |
15
mhycy 2015-07-06 11:48:44 +08:00
@dangyuluo
我个人会把那两个用“|”分割的属性拆成两个表。 输出的时候用join,但是有人说这样做性能不好。 我并没有足够的数据量进行对比,所以这个不好说。 现在这样也可以直接拆|然后用in的方式在数据库中查出属性。 当然,如果一个页面有多个这样的属性还是用map性能好一些 具体情况具体分析了。 反正我是不会主动选择这样的建表方式的 |
16
realpg 2015-07-06 13:05:37 +08:00 1
@mhycy join的性能不好主要是说被join的(一般说来是被关联字典表或者字典表地位的表)的行数以及范围,如果被关联的这个表行数比较小,一般我都是像楼主这样处理一下把这个表做到数组里
这种建表方式遇到过,主要是为了照顾其他模块的,然后设计时候2了没冗余一些相关列,楼主这个的需求是后提出的,就容易这样了 楼主的解决方案应该是没其他给定条件下的比较高效率的了 |
17
alphonsez 2015-07-08 05:33:58 +08:00
@mhycy 如果一个商家下面有上千个product,并且不做paging,怎么展示呢?我做过的项目里最终从DB出来的数据集都不大,几百个最多了,这种情况下iterate一遍的开销可以忽略不计了。
这个貌似可以常驻内存,定期刷新,刷的时候iterate一遍的开销相对于整个刷新而言,还是忽略不计。 按照一楼的例子,可以想一下,如果赋值做两遍: while ($ret = mysqli_fetch_array($query, MYSQLI_ASSOC)) { $retlist[$ret['id']] = $ret['name']; $retlist[$ret['id']] = $ret['name']; } 会慢很多吗? 如果一个写一个循环: for (int i = 0; i < 100; ++i) { } 会担心慢吗?如果都不会,那本来的写法其实就不会慢很多啦…… 关于这类内存操作的速度,如果真的不放心,可以实际测一下。记得和数据库操作的latency对比着看哦,不然没有意义。 |