Oracle SQL Developer 这个工具我用了七八年从最早还要自己配 JDK 的 4.x 版本一路用到现在的 23.x中间也认真试过 PL/SQL Developer、Navicat、DBeaver最后还是把它留成了主力客户端。理由说起来不复杂免费、不挑机器、解压就能跑而且对 Oracle 那些特有的东西——执行计划、PL/SQL 调试、会话管理、数据泵向导、迁移工作台——支持得最透。日常开发里查数据、改表结构、导结果集、调存储过程九成以上的活儿它都能接住也不需要为授权和激活分心。这篇文章我打算按从装到用、从连库到排错的顺序讲一遍重点放在那些官方文档里不太写、但实际每天都会碰到的细节上免安装版的配置藏在哪、CtrlEnter和F5到底差在哪、导出的身份证号为什么变成科学计数法、ORA-28547 这类报错从哪冒出来、11g 和 12c 的分页写法差在哪。不管你是刚接触 Oracle 数据库的新手还是用惯了别的客户端想换过来的人看完应该都能直接上手不用再来回翻手册。1. 为什么最后留在 SQL Developer 这个工具上1.1 免费和轻量这两个词实际体验到底是什么样先说免费这件事。SQL Developer 是官方出的图形化客户端下载页面上直接给安装包没有什么试用期、激活码、注册机之类的环节。这一点在团队里推的时候特别省事你不需要给新人解释授权规则也不用担心某个授权到期导致一群人打不开工具。对于个人练手、教学环境、中小型项目来说这个门槛低到几乎可以忽略。再说轻量。Windows 版现在有with JDK的包下载完解压双击sqldeveloper.exe就能起来全程不依赖你机器上已装的 Java 环境也不需要装 Oracle 客户端、不需要配ORACLE_HOME、不需要折腾tnsnames.ora。这一点很多人没意识到有多重要以前用某些客户端连库第一步就要装一个几百兆的 Instant Client配环境变量、配NLS_LANG光是让工具认识数据库就要花掉半天。SQL Developer 走的是 JDBC 瘦驱动纯 Java 实现直接跳过这一整套。它的插件机制也算一个加分项。默认装完就带了数据模型图、移植工作台、SVN/Git 版本控制集成这些扩展需要更多能力的时候在帮助-检查更新里挑几个装上就行不用去第三方站点找包。对日常工作来说这已经够用了。1.2 它到底能覆盖哪些日常活儿我把平时在它里面干的事列一遍你对照自己的场景看能对上多少。连库之后浏览表、视图、序列、同义词、包、触发器等所有对象右键就能看定义、看依赖、看数据。在一个工作表里写 SQL、跑 SQL、改结果集结果集网格里直接双击改值、加行、删行。用向导建表、建索引、建约束也可以生成对应的 DDL 语句对比。导出查询结果为 CSV、Excel、JSON、XML、SQL 脚本导入外部文件到表。编译并单步调试存储过程、函数、包看变量值、设断点。看执行计划、看会话、杀会话、看锁等待。生成表的数据模型图导出成图片给同事看。用迁移工作台把别的库的对象转成 Oracle 语法做初步评估。你会发现这个列表里几乎没有看起来很强但平时用不上的功能全是日常切口。这也是我留下来的核心原因它不试图做一个全能 IDE而是把 Oracle 生态里那几件最常做的事做扎实。下面几章我就按使用顺序把这些事一个个拆开讲。2. 安装之前必须先想清楚的几个点2.1 JDK 版本怎么选别在启动这一步卡住现在官网下载页上Windows 版通常提供两个包一个是带 JDK 的一个是不带 JDK 的。新手我强烈建议直接下带 JDK 的那个文件名里一般有with JDK字样体积大一些但省心。原因很简单SQL Developer 每个大版本对 JDK 的最低要求不一样19.x 之后基本要求 JDK 8 以上23.x 的一些新版本对 JDK 11 或 17 更友好。如果你自己去装 JDK很容易装成机器上已经有的一套旧版本然后启动时报一堆类加载或者模块相关的错误。如果你确实要用不带 JDK 的包比如公司统一要求那就需要在解压目录下的sqldeveloper/bin/sqldeveloper.conf里指定 Java 路径加一行SetJavaHome指向你的 JDK 目录注意路径分隔符要用正斜杠或者双反斜杠写错了整个工具起不来。Mac 和 Linux 版一般也给.zip或者.rpm/.deb逻辑是一样的Linux 下有时候还要注意 JDK 的位数和系统位数别搞反。注意机器上装了多个 JDK 时不要指望 SQL Developer 自动挑对。它会优先用配置文件指定的那个没配就用环境变量里的JAVA_HOME再不行才去系统 PATH 里找。出问题时第一件事就是去确认它到底用了哪个 Java。2.2 下载哪个包别跟其他东西搞混下载页面上东西不少容易点错。你要找的是名字里带 SQL Developer 的那一个不要点到 Oracle Database 的客户端、也不要点到 SQLcl 命令行工具虽然 SQLcl 也很好用但那是另一个东西。Windows 版认准.zip后缀带with JDK的包Mac 版同样Linux 有.rpm和.zip两种。另一个容易踩的点是版本和数据库的匹配。SQL Developer 连 11g、12c、19c、21c 这些库都很顺因为它用的是 JDBC 瘦驱动对数据库版本没那么挑。但如果你要用它去连很老的库比如 9i、10g那就得注意驱动兼容性必要时在首选项里换一个旧版 JDBC 驱动。一般开发环境不会遇到这种事知道有这回事就行。2.3 免安装版最实用的一个细节配置文件放哪这是我最想分享的一条经验SQL Developer 的安装目录和配置目录是分开的。安装目录就是你解压出来的那个文件夹删了重装没影响真正的个人数据——你保存的所有连接、代码片段、快捷键、字体设置、最近打开的 SQL——都存在用户目录下。Windows 上在%APPDATA%\SQL DeveloperLinux 和 Mac 上在~/.sqldeveloper。换电脑、重装系统、升版本之前把这个目录整个拷走装完新版本再放回去你的连接和片段就全回来了。我从 4.x 升到 23.x 就是这么干的几十个连接一个没丢代码片段里的常用 SQL 模板也都在。提示连接信息里的密码默认是加密存的如果换了机器上的用户名或者加密密钥变了可能需要重新输一次密码。连接本身的地址、端口、服务名不会丢。3. 建第一个连接填错一个字段就连不上3.1 连接类型和字段怎么填新建连接的时候连接类型下拉框里有好几个选项最常用的是基本Basic。它要你填四样东西主机名、端口、服务名或 SID、用户名密码。主机名填localhost或者数据库服务器的 IP 或域名端口默认1521这两个基本不会错。真正容易填错的是第三个字段。这里有个下拉框让你选服务名还是SID很多人不假思索选了默认值然后连接报错。这里必须说清楚区别SID 是数据库实例名服务名是数据库向监听器注册的对外的名字。11g 之后官方推荐用服务名因为服务名能支持集群和动态注册SID 是实例级的、绑死在具体实例上的。如果你不确定该用哪个去服务器上执行lsnrctl status输出里Service xxx has 1 instance(s)那个就是服务名。填错的话报错很有规律选错成 SID 一般报ORA-12505: TNS:listener does not currently know of SID given in connect descriptor服务名写错一般报ORA-12514: TNS:listener does not currently know of service requested in connect descriptor。看到这两个第一反应就去核对服务名或 SID别去怀疑网络。报错码通常原因优先检查ORA-12505SID 写错或实例没注册服务器上lsnrctl status的实例列表ORA-12514服务名写错或数据库没启动服务名拼写、数据库实例状态ORA-12541监听器根本没起或端口不通1521 端口是否在监听ORA-12170网络层超时防火墙、跨网段路由ORA-28000账号被锁用管理员账号解锁3.2 测试连接前先把监听确认一遍监听服务无法启动这个事几乎每个装过 Oracle 的人都遇到过现象是客户端连接报ORA-12541: TNS:no listener服务器上看服务也起不来。排查起来按这个顺序来先看监听进程在不在。命令行执行lsnrctl status如果提示找不到命令说明环境变量没配好直接进$ORACLE_HOME/bin目录下执行。如果提示TNS-12541或者连自己都连不上那监听确实没起来用lsnrctl start起一下看它报什么错。最常见的两个原因一个是端口被占用。Windows 上用netstat -ano | findstr 1521看谁占了Linux 上用netstat -tlnp | grep 1521。1521 被别的服务占了监听自然起不来要么改端口要么把占用的服务停掉。另一个原因是listener.ora里的 HOST 写的是主机名而这台机器的主机名解析不了——这种情况特别隐蔽日志里只会写解析失败不会直说。把 HOST 改成 IP或者去 hosts 文件里把这个主机名指到 127.0.0.1问题就没了。3.3 ORA-28547 这类报错从哪冒出来ORA-28547: connection to server failed, probable Oracle Net admin error这个报错有意思的地方在于它一般不出现在默认配置下。SQL Developer 默认用的是瘦Thin驱动纯 Java 实现压根不走 Oracle Net 那一层所以正常情况下你根本见不到它。它会冒出来通常是因为有人在首选项里把连接类型改成了OCI/Thick也就是让 SQL Developer 去调用本地的 Oracle 客户端库这时候如果客户端目录就是 Instant Client 或完整客户端所在目录没配、或者配错了、或者客户端版本和数据库差得太远就会撞上这个错。解决办法很直接打开工具-首选项-数据库-高级把连接类型改回Thin重启工具再连。除非你确实需要用到 Thick 驱动才能做的功能比如某些高级安全认证否则没必要碰它。还有一个类似的坑是路径里带空格或中文。如果你把 Instant Client 解压到了一个路径带空格的目录比如Program Files下面Thick 驱动加载时会出问题。要配客户端的话路径尽量选D:\oracle\instantclient这种干净的写法。4. 上手第一天就该掌握的界面操作4.1 工作表里 CtrlEnter 和 F5 的区别这个坑最深这是我认为最值得单独拿出来讲的一点因为它真的坑过太多人包括我自己。在工作表里写 SQL你有两种执行方式。按CtrlEnter有些版本是F9是运行语句它只跑光标所在的那一条语句结果以网格形式返回这个网格是可编辑的你改了值点提交就能写回数据库。按F5是运行脚本它把整个工作表当作一个脚本文件从头到尾执行结果以纯文本形式输出在下面的脚本输出窗口里像 SQL*Plus 那样。这个区别带来的后果很具体。你写了一句UPDATE t SET status 1 WHERE id 100;如果按F5跑它是脚本执行照样生效如果按CtrlEnter跑它在网格里显示1 row updated也是生效的。但如果你在工作表里写的是建表、建索引、插入数据这类语句两种方式的表现就完全不一样了F5会把这些 DDL 和 DML 顺序执行完而CtrlEnter一次只处理一条。更关键的是事务。CtrlEnter执行完之后SQL Developer 默认不会自动提交你需要手动点一下提交按钮工具栏上那个带箭头的绿色图标快捷键是F11或者按CtrlEnter之后再看到网格是黄色的提示状态。忘了提交别人就查不到你改的数据还会在表上留锁。我见过有同事改完数据下班第二天发现锁了一整晚就是没提交。注意想省事可以在工具-首选项-数据库-高级里把自动提交勾上但我不建议在生产环境里这么做。手动提交虽然多按一下但能给你一个反悔的机会。4.2 对象浏览器和表数据编辑比想象中好用左侧的对象树是数据库的目录把视图-连接打开右键某个连接选连接树就展开。点开表你会看到所有表右键一张表有几个特别常用的动作查看数据、编辑、查看定义、生成 DDL。查看数据打开的是只读网格编辑打开的是可写网格。可写网格里有几个操作值得记住。双击单元格就能改值右键行可以插入一行、复制一行、删除行左上角有个筛选输入框输入name like A%回车就过滤。改完之后提交注意提交按钮。还有一个细节如果你的表没有主键SQL Developer 改数据时会提示此表没有唯一标识无法安全更新这时候要么给表加主键要么在右键编辑的时候手动勾选一个能唯一定位的列作为行标识。这个细节看起来小但没主键的表在老系统里非常常见。导航那一块也有个实用技巧。对象树顶部的筛选框可以输入对象名快速定位支持通配符比如输入EMP%就能过滤出所有以 EMP 开头的表。一个库里几百张表的时候这个比滚动快得多。5. 查询和导出的高频场景实操5.1 导出的身份证号变成科学计数法怎么彻底解决这是被问得最多的一个问题。场景很典型你查出来一列身份证号导出成 CSV用 Excel 打开18 位数字变成了1.10101E17这种样子末尾几位还全变成 0。先把责任分清楚这不是 Oracle 的问题也不是 SQL Developer 的问题是 Excel 的机制。Excel 单元格默认按数值处理而数值类型只有 15 位有效精度18 位身份证号超了后面的位数就被截断成 0同时用科学计数法显示。解决方案按好用程度排个序。最省事的是导出时选 xlsx 格式而不是 CSVSQL Developer 的导出向导里格式下拉框里有Excel 2003这个选项生成的是真正的 Excel 文件同时它还提供一个作为文本导出的勾选项勾上之后所有字段都按文本写身份证号自然就完整了。如果你必须用 CSV比如下游系统只认 CS1 格式那就从 SQL 侧解决让导出内容自带让 Excel 识别成文本的标记SELECT id, || id_card || AS id_card FROM person_info;Excel 打开 CSV 时看到...这种写法会按公式处理结果就是一段纯文本不会丢精度。缺点是这列在 Excel 里长得像公式如果下游还要做别的处理可能不太方便。还有一个更稳的路子不要双击 CSV 直接打开。先开一个空白 Excel把身份证那一列整列选中右键设置单元格格式选文本然后再用数据-从文本/CSV导入导入向导的第三步里把该列指定为文本格式。这样从入口就把类型定死了一点不会出问题。这三招你按场景挑一个用就行。提示导出前先看一眼目标列的类型。如果数据库里这列本身就是VARCHAR2导出的内容就是字符串问题只出在 Excel 识别环节如果这列是NUMBER那就先在 SQL 里TO_CHAR转成字符串两边一致了再导。5.2 分页查询12c 和 11g 的写法差别很大Oracle 的分页是老生常谈但 12c 前后写法完全不同很容易在升级后写错。如果你用的是 11g传统的两层ROWNUM嵌套是标准做法SELECT * FROM ( SELECT a.*, ROWNUM rn FROM (SELECT id, name FROM t ORDER BY id) a WHERE ROWNUM 30 ) WHERE rn 20;这里有两个必须记住的约束。排序必须放在最里层不能放到外面否则分页结果是乱的ROWNUM 30必须写在内层不能写成外层rn 30因为ROWNUM是在结果集生成过程中分配的外层过滤时它已经固定了写法不对会返回空结果。这两条是新手写分页最常踩的坑。12c 之后有了标准的OFFSET ... FETCH语法干净多了SELECT id, name FROM t ORDER BY id OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;从 20 条之后开始跳过 20 条取 10 条也就是第 21 到 30 条。这个写法可读性好而且在 SQL Developer 里按CtrlEnter跑起来很直观。要注意的是OFFSET/FETCH必须和ORDER BY一起用没写ORDER BY会直接报语法错误这是规范强制的反而帮你避免了分页顺序不确定的问题。5.3 把一列按逗号拆成多行表里存了个codes列值是A,B,C,D要拆成四行。这种需求在做权限、标签、多值字段的时候特别常见。11g 之后可以用正则加层级查询做SELECT t.id, REGEXP_SUBSTR(t.codes, [^,], 1, lv) AS code FROM t, (SELECT LEVEL lv FROM dual CONNECT BY LEVEL 100) n WHERE lv REGEXP_COUNT(t.codes, ,) 1;思路是外层为每一行生成一个序列序列长度等于逗号数量加一然后用REGEXP_SUBSTR按位置取第 n 段。[^,]表示取连续的非逗号字符第四个参数lv指定取第几段。这里那个CONNECT BY LEVEL 100是上限如果你的字段最长可能有 200 段就把它调大。这个数字不是随便写的设小了会丢数据设大了会多算几行再被WHERE过滤掉性能上有点浪费。12c 之后可以用LATERAL写得更清楚SELECT t.id, x.code FROM t CROSS JOIN LATERAL ( SELECT REGEXP_SUBSTR(t.codes, [^,], 1, LEVEL) AS code FROM dual CONNECT BY LEVEL REGEXP_COUNT(t.codes, ,) 1 ) x;写起来更贴近思路读的人一眼能看懂。两种都行看你手上的库版本。5.4 数据重复就不插入几种写法的取舍批量同步数据的时候经常需要存在就跳过、不存在就插入。最直接的是INSERT ... WHERE NOT EXISTSINSERT INTO t (id, name) SELECT 1, Alice FROM dual WHERE NOT EXISTS (SELECT 1 FROM t WHERE id 1);简单、好懂缺点是单条执行循环插几千条的时候性能一般。数据量大就用MERGE一次处理整批MERGE INTO t USING (SELECT :id AS id, :name AS name FROM dual) s ON (t.id s.id) WHEN NOT MATCHED THEN INSERT (id, name) VALUES (s.id, s.name);MERGE的好处是语义清晰、一次读一次写适合从临时表或视图同步数据。要注意它在并发下并不等于绝对安全两个会话同时判断不存在然后同时插入还是可能撞唯一键约束。所以目标表上的唯一索引或主键必须存在这是最后一道防线出了问题至少数据是干净的捕获异常重试即可。注意用MERGE的时候别把WHEN MATCHED THEN UPDATE顺手加上除非你确实想覆盖已有数据。我见过有人从别处复制模板把不该更新的字段一起更新了事后靠闪回才救回来。6. PL/SQL 调试和性能观察6.1 存储过程单步调试怎么开SQL Developer 对 PL/SQL 的调试支持是它相对其他客户端的一个明显优势。前提是你要有调试权限普通开发账号通常需要被授予DEBUG CONNECT SESSION和DEBUG ANY PROCEDURE这两个权限没有的话调试按钮点了没反应或者报权限错误先找 DBA 开一下。流程是这样的在左侧对象树里找到目标过程或函数右键先编译如果编译报错错误会列在下面的日志里点错误能跳到具体行。编译通过之后再右键选编译并调试工具会打开一个调试窗口里面有源代码、断点区、变量监视区和调用栈。在行号左边点一下就能设断点然后点调试工具栏上的执行按钮程序会在断点处停下来你把鼠标悬在变量上就能看到当前值也能在变量窗口里手动加表达式观察。包Package稍微特殊一点。如果断点设在包头声明里那是没用的要调试包体里的过程得先对整个包体做一次编译并调试让调试信息生成出来然后再进具体过程设断点。很多人第一次调试包的时候设了断点没停下来就是漏了这一步。还有一个小细节值得提醒调试会话是独占的调试期间那个过程的执行会挂在断点上如果这个存储过程被定时任务或者别的人在调可能会导致对方等待。调试生产环境的东西要格外小心尽量在测试库做。6.2 执行计划怎么看才算看懂在 SQL Developer 里写完 SQL 按CtrlEnter执行然后点工具栏上的解释计划按钮快捷键F10就能看到这条语句的执行计划。默认显示的是预估行数也就是优化器猜的数字参考价值有限。想看真实的执行情况更好的做法是开启统计信息收集然后执行语句再把游标缓存里的真实计划打出来SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, ALLSTATS LAST));这条语句要在同一个会话里、同一条 SQL 执行过之后马上跑。ALLSTATS LAST会把预估行数和实际行数放在一起对比。判断计划好坏的第一眼就看这个对比如果预估 1 行实际 100 万行说明统计信息过期或者有隐式类型转换优化器选错了路径。这种偏差是性能问题的头号来源比单纯看有没有走索引更值得关注。看计划的时候另外几个要点TABLE ACCESS FULL不一定是坏的小表全扫比走索引快NESTED LOOPS适合驱动结果集小的情况HASH JOIN适合两个大表关联。别一看到全表扫描就去加索引先看实际行数和逻辑读逻辑读高才是真的有问题。7. 常见问题速查和独家避坑7.1 连接类问题的排查顺序连不上数据库的时候我一般按这个顺序走能覆盖九成的情况。第一步确认服务端监听在跑。服务器上lsnrctl status看状态Service xxx has 1 instance(s)这种输出说明正常。第二步确认网络通。在本机用telnet 主机 1521测端口通了说明链路没问题不通就去查防火墙和路由。第三步确认服务名或 SID 拼写。第四步确认账号状态ORA-28000就是被锁了。第五步看客户端用的是 Thin 还是 Thick 驱动Thick 驱动配置错误会报 ORA-28547。现象大概率原因处理动作一直卡在正在连接网络不通或防火墙拦截用 telnet 测 1521 端口ORA-12541监听没起服务器上lsnrctl startORA-12505 / ORA-12514SID 或服务名填错对照lsnrctl status输出核对ORA-28000账号被锁管理员ALTER USER ... ACCOUNT UNLOCKORA-28547Thick 驱动配置有问题改回 Thin 驱动连接成功但查询乱码字符集不匹配检查数据库 NLS 字符集和客户端设置7.2 显示和编码类问题中文乱码是个老问题。数据库字符集是AL32UTF8、客户端NLS_LANG设成 GBK 或者反过来都会导致查出来的中文是问号或者方块。在 SQL Developer 里因为走的是 JDBC一般不依赖NLS_LANG但如果服务器字符集和 JDBC 连接的字符集对不上还是会乱。这时候可以在连接的高级属性里加一个oracle.jdbc.defaultNChartrue或者在首选项里把编码设成 UTF-8。另