随着MYSQL 从互联网圈蔓延出来,小作坊的软件开发机构也想使用MYSQL 来作为软件开发的数据库选择项。5年前可以选择的数据库种类并不多,ORACLE, 数据库收费,太笨重,小型开发一般很难选择他。 SQL SERVER 作为很多软件供应商的也是有原因的,价格不是很贵,不懂的上手也死不了人,就算SQL 写的再烂,SQL SERVER 敢为孺子牛的气质,至少还能让你跑起来。有些软件开发企业,就算用ORACLE 也挽救不了对数据库白痴的使用行为,开发出烂的出奇的SQL,你还不能改,美其名曰,知识产权,其实都嵌入在程序里面改不了,数据量少还好,数据量一大(其实也不大有的三四个月就现原形),可惜人家早就拿钱跑了,你在问,那就是各种托词,你们不会使用了,你们维护有问题了。
作为近几年MYSQL的大行其道,在软件开发企业(作坊)不仅仅不知道收敛,还愿意使用MYSQL 作为开发的数据库。 呵呵,题目就是,没有金刚钻,你别揽瓷器活,使用MYSQL 那是个技术活,有些机构真的干不了,下面就是某个机构给公司开发的系统,里面的SQL。细数这些人干的活。
白痴行为1
不懂MYSQL 底层存储结构设计,拿ORACLE 的生搬硬套,结果:那是死的想当难看。
你见过使用MYSQL 设计表,用varchar(32) 做主键的吗? ,不光如此,还要用这个VARCHAR32 来存储一堆无序的字符,美其名曰,快速散列插入,那真是脑子进水了,更奇葩的,还有拿两个字段来作为主键的,还都是VARCHAR(32) , 麻烦别再害人了。 你是开发走人了,你让买你软件的,运维死去活来,违背原理让数据的插入,和更新都慢出了新水平。
更新一行数据要 32秒,OMG ,打破世界吉尼斯纪录 ? 诸位上上眼,就是这条SQL ,上了慢查询纪录,就没快过 6秒,
update cx_base_voice_missing m set m.stauts=0
where m.callNumber in
(SELECT DISTINCT t.CALLER
FROM `cx_bas_voice_seq` t
where left(t.START_TIME,10)=DATE_FORMAT(NOW(),'%Y-%m-%d') and t.VOICE_DIRECT_ID='CX_BAS_CHANNEL_DIR_INBOUND' and t.UNIT_ID='khfwb')
and
m.callednumber='65276777'
and
m.callDay=DATE_FORMAT(NOW(),'%Y-%m-%d')
and m.stauts=1\G
这里不光说你,也教教你怎么设计MYSQL的UPDATE ,首先不能在UPDATE 里面有JOIN ,子查询,利用查询查出你需要更新的数据行的主键,然后在UPDATE 数据用主键做条件。 当然如果懒到你只能写出上面的语句,不用脑子的,麻烦你还是用ORACLE ,SQL SERVER 吧
以上还算能原谅,程序员不懂MYSQL的数据存储结构,以前只开发使用ORACLE ,SQL SERVER。
白痴行为2
下面的语句又怎么解释
SELECT d.connectionid voice_id
,case when d.calltype=1 then 'CX_BAS_CHANNEL_DIR_INBOUND' else 'CX_BAS_CHANNEL_DIR_OUTBOUND' end VOICE_DIRECT_ID
,d.ringingstarttime RING_TIME
,d.answertime START_TIME
,d.callendtime RELEASE_TIME
,date_add(d.callendtime, interval 3 second) END_TIME
,case when d.answertime is null then TIMESTAMPDIFF(SECOND, d.ringingstarttime,d.callendtime) else TIMESTAMPDIFF(SECOND, d.ringingstarttime,d.answertime) end RING_LONG_TIME
,3 AFTER_LONG_TIME
,TIMESTAMPDIFF(SECOND,d.answertime,d.callendtime) LONG_TIME
,d.connectionid CALL_ID
,d.staffename AGENT_NAME
,d.staffeId staffid
,case when d.calltype=1 then d.agentid else
case when (LEFT(d.callednumber,3) in('013','015','016','017','018') and
LENGTH(d.callednumber)=12) then substring(d.callednumber,2,11) else d.callednumber end
end callee
,sf.unitid unitid
, case when d.calltype=1 then
case when (LEFT(d.callingnumber,3) in('013','015','016','017','018') and
LENGTH(d.callingnumber)=12) then substring(d.callingnumber,2,11) else d.callingnumber end
ELSE d.agentid END caller
,'VOICE' CHNL_ID
,case when d.recordpath is null then null else CONCAT('/zxinrecwav/rec/',d.recordpath) end VOICEFILEPATH
from cc_agentcalldetail d
LEFT JOIN cx_bas_staff sf on d.staffeId=sf.staff_id
where d.connectionid not in (
SELECT t.call_id FROM `cx_bas_voice_seq` t
where left(t.RING_TIME,11)=DATE_FORMAt(now(),'%Y-%m-%d'))
and
DATE_FORMAT(d.ringingstarttime,'%Y-%m-%d')=DATE_FORMAt(now(),'%Y-%m-%d')
and (d.calltype=1 or d.calltype=6) and d.staffeId<>'1001'\G
这个SQL 蠢到在 where 条件等式左边进行计算,这个是不能原谅的,SQL SERVER ,MYSQL , ORACLE ,那个数据库告诉你这样可以走索引了。不光MYSQL 不懂,常用的数据库也是一塌糊涂,给你哪个数据库都能让你搞砸。
白痴行为3
select count(*) as col_0_0_
from CX_BAS_VOICE_SEQ cxbasvoice0_
where 1=1
and
cxbasvoice0_.STAFFID<>'donglingling'
and
length(cxbasvoice0_.VOICEFILEPATH)>0
and
cxbasvoice0_.UNIT_ID='Credit' and (cxbasvoice0_.VOICEFILEPATH is not null)
and
not (exists (select 0 from CX_QUALITY_ALLOT_GRADE_INFO grade1_
where grade1_.QUALITY_RELATE_ID=cxbasvoice0_.VOICE_ID))\G
这个SQL 就更有意味了,相信就是ORACLE SQL SERVER DBA 看到这样的SQL 也能称赞,写着SQL的 程序员哥们,已经蠢的赏心悦目了。
麻烦MYSQL SELECT COUNT(*) 的时候别用 * 用主键。表设计的时候要不要懒到连个默认值都没有,然后一会儿 IS NOT NULL ,一会儿 IS NULL。你不光给自己找麻烦,也让别人知道你公司的开发水平,已经低到地平线低下了。
MYSQL 的索引不是你想怎样建就怎样,写语句WHERE 条件也是要顺序的,先等于,在RANGE ,好不要 ORDER BY DESC ,尽量不要GROUP BY ,不需排序 加ORDER BY NULL,单个索引能解决,就不要去复合,一个MYSQL 表一行大的索引容量是多少,想想他也不知道。
——————————————————————————————
结语:中标之前,甜言蜜语,拿钱之后,逃之夭夭,横批,自有开发靠谱。
对不负责的第三方开发机构