mnesia的index_read的性能问题
catch _:_ ->
???????? ??? {not_granted, {no_exists, Tab, {index, [Pos]}}}
??? end;
…
?
锁请求返回时,事务线程的处理:
mnesia_locker.erl
rlock_get_reply(Node, Store, Tab, {granted, V, RealKeys}) ->
??? %% Kept for backwards compatibility, keep until no old nodes
??? %% are available
??? L = fun(K) -> ?ets_insert(Store, {{locks, Tab, K}, read}) end,
??? lists:foreach(L, RealKeys),
??? ?ets_insert(Store, {nodes, Node}),
??? V;
返回值即为查找到的行记录。
由此可见mnesia的索引存在的问题,即index_read为表锁,极大地影响并发,应慎用。
?
?
这里总结一些mnesia的使用注意事项:
1.一次事务读的行记录越少越好,跨越的表越少越好,因为每一次读都会产生一个读锁,记录和表越多,与写锁冲突的几率就越大,阻塞写的几率就越大;
2.如果多个表的主键相同,应该尽量将这些表合并,除非:
a)表的规模可能很大,导致一个ets表存不下这些数据,此时可以考虑拆字段或按id切分;
b)表只有很少的字段会频繁读到,一次读出全部内容的几率很小;
c)关于此条,也可以结合数据库表设计原则进行,但设计时一定要注意,mnesia只是一个kv存储;
3.不要用index_read,因为index_read会锁住全表,并严重阻塞写操作,使得读写较为平均的并发受到很大限制。如果需要索引,那么存两张表,一张专门用于索引,索引与主键一一映射;
4.majority表使用majority事务,这个事务至少有两次同步的网络请求和一次异步的网络请求,这个代价较大,而普通事务只有一次同步的网络请求和一次异步的网络请求,同步事务有两次同步的网络请求;
5.mnesia事务内部的操作应越短越好,因为访问的记录产生的锁只在事务提交时释放,如果内部无关操作太多,可能会阻塞其它请求;
?
?