<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.3">Jekyll</generator><link href="https://method5.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://method5.github.io/" rel="alternate" type="text/html" /><updated>2024-01-25T21:05:13+00:00</updated><id>https://method5.github.io/feed.xml</id><title type="html">Method5</title><subtitle>Remote execution for Oracle SQL</subtitle><entry><title type="html">Avoiding Oracle Quines</title><link href="https://method5.github.io/Avoiding-Oracle-Quines/" rel="alternate" type="text/html" title="Avoiding Oracle Quines" /><published>2018-06-09T00:00:00+00:00</published><updated>2018-06-09T00:00:00+00:00</updated><id>https://method5.github.io/Avoiding-Oracle-Quines</id><content type="html" xml:base="https://method5.github.io/Avoiding-Oracle-Quines/">&lt;p&gt;Unexpected quines can appear when querying tables like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;V$SQL&lt;/code&gt;.  To avoid them you must sometimes add an extra predicate to those queries:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;	&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;sql&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql_fulltext&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;like&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%quine%'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;what-is-a-quine&quot;&gt;What is a Quine?&lt;/h2&gt;

&lt;p&gt;A quine is a program that outputs its own source code.  Normally it’s a form of code golf; a challenging, impractical puzzle to entertain programmers.  They’re usually hard to create and look cryptic.&lt;/p&gt;

&lt;p&gt;Here’s a Python 2 example.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'_=%r;print _%%_'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;See &lt;a href=&quot;https://en.wikipedia.org/wiki/Quine_(computing)&quot;&gt;this Wikipedia article&lt;/a&gt; or &lt;a href=&quot;https://codegolf.stackexchange.com/questions/69/golf-you-a-quine-for-great-good&quot;&gt;this Code Golf question&lt;/a&gt; for more details and examples of quines.&lt;/p&gt;

&lt;h2 id=&quot;how-do-they-happen&quot;&gt;How Do They Happen?&lt;/h2&gt;

&lt;p&gt;Quines can happen when querying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;V$SQL&lt;/code&gt;, because the query will match its own conditions.  For example, this query searches for all recent SQL statements that reference the table “FOO”:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;	&lt;span class=&quot;k&quot;&gt;SQL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;no&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;selected&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;SQL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql_text&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;sql&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql_fulltext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;like&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%foo%'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;SQL_ID&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;SQL_TEXT&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;------------- --------------------------------------------------------------------------------&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;83&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zk38bvaq4nu&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zadv09qpyc9a&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql_text&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;sql&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql_fulltext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;like&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%foo%'&lt;/span&gt;

	&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;selected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Before the query against V$SQL was run, it was parsed and put in V$SQL, which is why it found itself.  These recursive problems are weird and take a while to get used to.&lt;/p&gt;

&lt;h2 id=&quot;how-do-we-stop-them&quot;&gt;How Do We Stop Them?&lt;/h2&gt;

&lt;p&gt;Stopping the quines is easy.  Simply add another predicate that will exclude itself:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;	&lt;span class=&quot;k&quot;&gt;SQL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;alter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;system&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flush&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shared_pool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;System&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;altered&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;SQL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;no&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;selected&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;SQL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql_text&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;sql&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql_fulltext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;like&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%foo%'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sql_fulltext&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;like&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%quine%'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;SQL_ID&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;SQL_TEXT&lt;/span&gt;
	&lt;span class=&quot;c1&quot;&gt;------------- --------------------------------------------------------------------------------&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;83&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zk38bvaq4nu&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;

	&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;selected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That extra predicate will look weird at first, but you’ll get used to it.&lt;/p&gt;

&lt;h2 id=&quot;why-does-it-matter&quot;&gt;Why Does it Matter?&lt;/h2&gt;

&lt;p&gt;There are many times when it’s necessary to search for SQL statements.  Usually it’s for ad hoc tuning or debugging, when it doesn’t make a big difference if there is one extra row.&lt;/p&gt;

&lt;p&gt;But occasionally you need to find one, and only one SQL statement, so you can do something with it.&lt;/p&gt;

&lt;p&gt;For example, sometimes in Oracle you want to force a hard-parse.  Normally it’s great that Oracle remembers your query, and can learn more on each execution.  But sometimes you don’t want it to remember anything.&lt;/p&gt;

&lt;p&gt;This can happen when you are running dynamic SQL in SQL, and the return types are not known until run time.  Since the return type can change over time, even for the same input, it’s important to flush the statements from the shared pool.  And to save time it helps to only flush the one statement that matters.&lt;/p&gt;

&lt;p&gt;This is used in Method5 because the function &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M5&lt;/code&gt; need to be re-parsed every time, in case it will return different values.  You can see this in action in the procedure &lt;a href=&quot;https://github.com/method5/method5/blob/88476099a5f979063bfc9d99cf70d4d1b7036e09/code/install_method5_objects.sql&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;method5.m5_purge_sql_from_shared_pool&lt;/code&gt;&lt;/a&gt;.  (There are a bunch of small objects in that file, search for “quine” to find it.)&lt;/p&gt;

&lt;p&gt;It’s not a common problem, and not incredibly important.  But it’s interesting to see spontaneously happen when it’s usually quite difficult to create intentionally.&lt;/p&gt;</content><author><name></name></author><summary type="html">Unexpected quines can appear when querying tables like V$SQL. To avoid them you must sometimes add an extra predicate to those queries:</summary></entry><entry><title type="html">Improve Entity-Attribute-Value models with proper data types</title><link href="https://method5.github.io/Improve-Entity-Attribute-Value-models-with-proper-data-types/" rel="alternate" type="text/html" title="Improve Entity-Attribute-Value models with proper data types" /><published>2017-11-14T00:00:00+00:00</published><updated>2017-11-14T00:00:00+00:00</updated><id>https://method5.github.io/Improve-Entity-Attribute-Value-models-with-proper-data-types</id><content type="html" xml:base="https://method5.github.io/Improve-Entity-Attribute-Value-models-with-proper-data-types/">&lt;p&gt;Entity-Attribute-Value (EAV) models are a contentious topic in database design.  Flexibility is important but some things should not be sacrificed.&lt;/p&gt;

&lt;p&gt;EAVs should use a table like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	NAME          VARCHAR2(4000)
	NUMBER_VALUE  NUMBER
	STRING_VALUE  VARCHAR2(4000)
	DATE_VALUE    DATE&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;EAVs should avoid a simpler table structure like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	NAME   VARCHAR2(4000)
	VALUE  VARCHAR2(4000)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Those extra columns don’t take away any of the benefits and alleviate many of the costs.&lt;/p&gt;

&lt;h2 id=&quot;pros-and-cons&quot;&gt;Pros and Cons&lt;/h2&gt;

&lt;p&gt;Here are some common arguments in EAV debates:&lt;/p&gt;

&lt;p&gt;Pros&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Flexibility to add anything without schema changes.&lt;/li&gt;
  &lt;li&gt;Looks nicer on the schema diagrams.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cons&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Data type errors&lt;/li&gt;
  &lt;li&gt;Bad performance.&lt;/li&gt;
  &lt;li&gt;Lack of constraints.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Architects and application developers prefer EAV and DBAs tend to hate it.&lt;/p&gt;

&lt;p&gt;The best design is a compromise.  Be honest about the importance of each pro and con.  While it is important to compromise on high level schema designs we should never compromise on low level type safety.&lt;/p&gt;

&lt;h2 id=&quot;flexible&quot;&gt;Flexible&lt;/h2&gt;

&lt;p&gt;Applications can still store anything.  Those 3 columns cover 99% of all data.  It’s easy to add more columns if necessary.&lt;/p&gt;

&lt;p&gt;Some people might complain that those extra columns create more work because you need to identify the type.  But in practice, if you have a single value you will almost always need to know the type anyway.  Even if the value will only be displayed on a screen the type is useful for justifying the text.&lt;/p&gt;

&lt;p&gt;If you truly have unstructured data it should still have a data type, such as JSON or XMLType.&lt;/p&gt;

&lt;h2 id=&quot;looks-nice&quot;&gt;Looks Nice&lt;/h2&gt;

&lt;p&gt;This reason usually isn’t that important.  Developers and DBAs typically use an IDE as the primary interface for the database, not the PDFs generated by the data modeling tool.&lt;/p&gt;

&lt;p&gt;But with the compromise solution this isn’t an issue, it only requires a few extra columns one time.&lt;/p&gt;

&lt;h2 id=&quot;data-type-errors&quot;&gt;Data Type Errors&lt;/h2&gt;

&lt;p&gt;This is a subtly dangerous issue that you may not discover until it’s too late.&lt;/p&gt;

&lt;p&gt;It is difficult to control the order a SQL query is executed.  Without that guaranteed order most developers will write unsafe queries like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select *
	from eav
	where name = 'Date of Birth'
	and value = date '2000-01-01';&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That query will &lt;em&gt;usually&lt;/em&gt; work.  But it is not guaranteed to work because Oracle may check the value predicate before the name predicate, and not all values can convert to dates.&lt;/p&gt;

&lt;p&gt;There is only one safe way to write that query:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select *
	from
	(
		select *
		from eav
		where name = 'Date of Birth'
		and rownum &amp;gt;= 1
	)
	where value = date '2000-01-01';&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That is the only safe way because ROWNUM is a special function that Oracle assumes means “these rows must be displayed in order”.  Oracle will never push a predicate or view merge into an inline view with a ROWNUM.&lt;/p&gt;

&lt;p&gt;No other fix will work reliably.  A simple inline view can be trivially rewritten by the optimizer.  The physical order of predicates is ignored.  Hints are difficult to get right.  Even a CASE statement does not always guarantee short circuit evaluation in SQL (despite what the manual says).&lt;/p&gt;

&lt;p&gt;Use the extra type-safe columns unless you want to write the ROWNUM trick a hundred times and are willing to thoroughly warn all SQL developers about the dangers in your data model.&lt;/p&gt;

&lt;h2 id=&quot;bad-performance&quot;&gt;Bad Performance&lt;/h2&gt;

&lt;p&gt;The extra type columns can significantly boost performance.&lt;/p&gt;

&lt;p&gt;The exact type will be smaller and slightly faster to compare than a converted string.&lt;/p&gt;

&lt;p&gt;The optimizer will have a little better information with the right types.&lt;/p&gt;

&lt;p&gt;Most importantly, the right types let you avoid the horrible ROWNUM trick.  That gives the optimizer more flexibility to transform the query and choose a better plan.&lt;/p&gt;

&lt;h2 id=&quot;lack-of-constraints&quot;&gt;Lack of Constraints&lt;/h2&gt;

&lt;p&gt;Using the right types doesn’t allow for smart constraints but at least it supplies some basic type checking.&lt;/p&gt;

&lt;p&gt;Validating dates and numbers is much harder than most developers realize.&lt;/p&gt;

&lt;p&gt;For dates, very few applications properly deal with internationalization.  For example, the month abbreviations are not the same in every language.&lt;/p&gt;

&lt;p&gt;For numbers, very few applications can handle all number formats.  Number validation sounds simple until you look at the Oracle manual’s complex syntax diagrams.  (Tip - those diagrams are helpful but contain a mistake.  If you can’t find it, don’t try to write a regular expression to handle number validation).  The Method5 PL/SQL lexer uses this regular expression.  But don’t use it, this is only an example of how horrible the regular expression will be.  It also doesn’t work with “+” or “-“, because the lexer considers those operators and not part of the number.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	([0-9]+\.[0-9]+|\.[0-9]+|[0-9]+)((e|E)(\+|-)?[0-9]+)?(f|F|d|D)?&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;always-use-the-right-type&quot;&gt;Always Use the Right Type&lt;/h2&gt;

&lt;p&gt;Using the default Oracle data types costs almost nothing, avoids type errors, improves performance, and simplifies validation.  Adding a few extra columns now can prevent a lot of problems later.&lt;/p&gt;</content><author><name></name></author><summary type="html">Entity-Attribute-Value (EAV) models are a contentious topic in database design.  Flexibility is important but some things should not be sacrificed.</summary></entry><entry><title type="html">The Difference Between Debugging and Performance Tuning</title><link href="https://method5.github.io/The-Difference-Between-Debugging-and-Performance-Tuning/" rel="alternate" type="text/html" title="The Difference Between Debugging and Performance Tuning" /><published>2017-10-18T00:00:00+00:00</published><updated>2017-10-18T00:00:00+00:00</updated><id>https://method5.github.io/The-Difference-Between-Debugging-and-Performance-Tuning</id><content type="html" xml:base="https://method5.github.io/The-Difference-Between-Debugging-and-Performance-Tuning/">&lt;p&gt;On the surface both performance tuning and debugging follow the same process: find a problem, drill down to the root cause, then fix or work around the underlying problem.&lt;/p&gt;

&lt;p&gt;But there’s a key difference between the two.  Programmers and administrators who don’t understand the difference tend to waste a lot of everyone’s time when they try to performance tune.&lt;/p&gt;

&lt;h2 id=&quot;debugging&quot;&gt;Debugging&lt;/h2&gt;

&lt;p&gt;When debugging you only need to find the &lt;strong&gt;first&lt;/strong&gt; problem and then drill down.  The program must work 100% correctly, if even a single byte looks wrong then it should be investigated.  Even if you don’t fix the problem you set out to fix you still accomplished something useful.&lt;/p&gt;

&lt;h2 id=&quot;tuning&quot;&gt;Tuning&lt;/h2&gt;

&lt;p&gt;For performance tuning you need to find the first &lt;strong&gt;significant&lt;/strong&gt; problem, and then drill down.  It’s easy to get distracted by weird behavior and wait events.  If you don’t fix the right problem you’ll waste a lot of time.&lt;/p&gt;

&lt;p&gt;The art of performance tuning is to gather relevant data and then ignore the 90% of the process that only accounts for 10% of the runtime.  And then ignore the 9% that is slow but is necessarily slow.&lt;/p&gt;

&lt;h2 id=&quot;motivated-troubleshooting&quot;&gt;Motivated Troubleshooting&lt;/h2&gt;

&lt;p&gt;There are many performance tuning dead ends.  I’ve seen many people, including myself, waste days fixing a problem that could not theoretically improve performance by a significant amount.&lt;/p&gt;

&lt;p&gt;We all have the urge to take the easy path and fix problems we are familiar with.  For bug fixing that’s usually a good idea - any cleanup is a good thing.  It can be helpful to have a utopian view of the code.&lt;/p&gt;

&lt;p&gt;But performance tuning must stay firmly grounded in reality.  And the ugly truth is that nobody will ever fully understand all the wait events or all the execution plan operations.  We only have time to fix the slow ones.  Don’t bother tracing the entire process, sampling is good enough.&lt;/p&gt;

&lt;p&gt;For personal education it’s helpful to investigate anything that doesn’t look right.  But when there’s a critical performance problem you must focus on the most important parts.&lt;/p&gt;</content><author><name></name></author><summary type="html">On the surface both performance tuning and debugging follow the same process: find a problem, drill down to the root cause, then fix or work around the underlying problem.</summary></entry><entry><title type="html">Use SQL Styles to Reduce Complexity</title><link href="https://method5.github.io/Use-SQL-styles-to-reduce-complexity/" rel="alternate" type="text/html" title="Use SQL Styles to Reduce Complexity" /><published>2017-06-30T00:00:00+00:00</published><updated>2017-06-30T00:00:00+00:00</updated><id>https://method5.github.io/Use-SQL-styles-to-reduce-complexity</id><content type="html" xml:base="https://method5.github.io/Use-SQL-styles-to-reduce-complexity/">&lt;p&gt;Use these slightly unusual styles to reduce the complexity of SQL code:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Avoid Abbreviations&lt;/li&gt;
  &lt;li&gt;Avoid Aliases&lt;/li&gt;
  &lt;li&gt;Use Inline Views&lt;/li&gt;
  &lt;li&gt;Tab Indenting&lt;/li&gt;
  &lt;li&gt;Lower Case&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These rules make sense when SQL code complexity is measured by something other than a simple character count, and when the legacy ideas of SQL are abandoned.&lt;/p&gt;

&lt;h2 id=&quot;avoid-aliases-and-abbreviations---words-are-the-atomic-unit-of-code&quot;&gt;Avoid aliases and abbreviations - words are the atomic unit of code&lt;/h2&gt;

&lt;p&gt;A word count is a better measure of complexity than a character count.&lt;/p&gt;

&lt;p&gt;Drilling down through the hierarchy of a program can go through many different paths.  A PL/SQL program has objects, objects have statements, statements have SQL, etc.  It’s easy to end up at a low-level concept like a character, byte, bit, etc.  But those concepts are too low level.&lt;/p&gt;

&lt;p&gt;Only complexity as perceived by a human is important.  In general, people think and operate on words, not characters.  We read words - except for weird words or children learning to read.  We type words without even thinking about the letters - except for people who don’t know how to type.  A large word is simpler than a few random letters put together.&lt;/p&gt;

&lt;p&gt;This statement:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select *
	from employee
	where employee.name = 'John Smith';&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Is simpler than this statement:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select *
	from employee e
	where e.name = 'John Smith';&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The first version has more characters but fewer words.  It also has one less variable, the “e”.  This is why aliases should typically be avoided.&lt;/p&gt;

&lt;p&gt;Now compare this statement:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select * from employee;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With this statement:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select * from emp;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Again the first statement has more characters.  But all English speakers instantly know what an “employee” is.  Reading the full word requires virtually no attention.  The abbreviation “emp” is simple but it still requires a tiny amount of thought.  Why make people think more than they have to?&lt;/p&gt;

&lt;p&gt;Abbreviations save characters but require more mental effort and take longer to type.  Unusual abbreviations should be avoided.&lt;/p&gt;

&lt;p&gt;Obviously the definition of “unusual” is subjective and depends on the context.  If every programmer on your project instantly recognizes an abbreviation then use it.  But don’t invent new ones for every SQL statement and table and don’t follow some “abbreviation guideline” that generates cryptic code.&lt;/p&gt;

&lt;h2 id=&quot;use-inline-views---measure-joins-with-chunks-and-factorials&quot;&gt;Use inline views - measure joins with chunks and factorials&lt;/h2&gt;

&lt;p&gt;Once a simple character count is abandoned it is possible to think about code in more logical ways.&lt;/p&gt;

&lt;p&gt;Compare the one-join-clause-to-rule-them-all approach:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select * from t1, t2, t3, t4, t5, t6 ...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;With an inline view approach:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select * from
	(
		select * from t1, t2, t3 ...
	) view1
	join
	(
		select * from t4, t5, t6 ...
	) view2
		on view1...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;(Ignore the old-fashioned Oracle join syntax for now.  ANSI joins are superior but that’s a separate topic.)&lt;/p&gt;

&lt;p&gt;The second version is not only bigger but has additional words, additional joins, and even repeats things.  Yet it is simpler for several reasons.&lt;/p&gt;

&lt;p&gt;First, think of inline views as the equivalent of procedures in a procedural language, or functions in a functional language.  Sets are the building blocks of SQL.  There is an elegance to nesting them and creating hierarchies of sets.  You wouldn’t use a single, ginormous procedure to do everything in a procedural language, don’t make a similar mistake in SQL.&lt;/p&gt;

&lt;p&gt;Next think about the different ways to join the tables.  There are 6! (6 factorial, or 6&lt;em&gt;5&lt;/em&gt;4&lt;em&gt;3&lt;/em&gt;2&lt;em&gt;1) ways to order the 6 table join, so there are roughly 720 ways to mentally visualize the tables.  Compared to 3!&lt;/em&gt;2, or roughly 12 ways to visualize the inline views.&lt;/p&gt;

&lt;p&gt;I wouldn’t say that version 1 is literally 720/12 times more complex than version 2.  But the complexity of adding tables to a join clause is not linear.  We all intuitively know this - at some point a function just gets too big.  It’s the same with join clauses.&lt;/p&gt;

&lt;p&gt;It can be helpful to think of code in terms of chunking.  Chunking is the idea that our minds constantly group things into chunks and we can only keep a small number of chunks in short term memory at the same time.  Research and common sense suggests the number is small, like between 5 and 7.&lt;/p&gt;

&lt;p&gt;So build small, intuitive chunks of SQL using inline views.  Join those chunks and repeat.  This only works with inline views because inline views take no input and have no side effects.  Think of them as pure functions.&lt;/p&gt;

&lt;p&gt;This benefit does not extend to correlated subqueries and the WITH clause.  Those features often make code more complex because they introduce side effects and tie everything together.  Both obviously have their place in SQL code.  But if you always use WITH clauses just to make your code read top-to-bottom you’re adding a lot of complexity.&lt;/p&gt;

&lt;h2 id=&quot;tabs-instead-of-spacing---indenting-is-for-showing-parent-child-relationships-not-random-text-alignment&quot;&gt;Tabs instead of spacing - indenting is for showing parent-child relationships, not random text alignment&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select ...
	from ...
	where ...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;vs.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select ...
	  from ...
	 where ...&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;To some people the spaces versus tabs debate boils down to: tabs are sometimes faster but spaces can make things look prettier.&lt;/p&gt;

&lt;p&gt;In general I believe in spending the extra time to make code look good but not in this case.&lt;/p&gt;

&lt;p&gt;First, the speed different between tabs and spaces is greater in SQL.  This is because SQL auto formatters suck and should be avoided (because SQL is too complex to parse, but that’s another topic.)  And beautifiers and IDEs won’t help you format dynamic code that looks like a string.  And in PL/SQL dynamic code is critical.  Avoiding dynamic SQL leads to some horrible anti-patterns.&lt;/p&gt;

&lt;p&gt;The beauty of spaces is an illusion.  The point of indenting is to show parent-child relationships and make it clear what code is on the same level.  Indenting with tabs and left-justifying keywords makes it abundantly clear what those relationships are.&lt;/p&gt;

&lt;p&gt;On a slightly related topic, this is why inline view parentheses should be on their own line like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	select *
	from
	(
		select ...
		from ...
	)&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Those parentheses are so important they deserve a separate line.  The code between them is an entire state and can exist separate from everything else in the query.  That inline view can be copied and pasted or debugged all by itself.  Inline views are the key to SQL - give them some space.&lt;/p&gt;

&lt;h2 id=&quot;use-lower-case---because-sql-is-important&quot;&gt;Use lower case - because SQL is important&lt;/h2&gt;

&lt;p&gt;Upper-casing SQL probably started because that’s how COBOL was written.  Today’s SQL is much better than it was in the 1980s, it’s time to break with the past and stop typing like an angry teenager.&lt;/p&gt;

&lt;p&gt;One current advantage to using upper case for SQL is to help contract it with other languages or writing.  For example, when quoted in this paragraph it looks better to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SELECT * FROM DUAL;&lt;/code&gt;  There’s no mistaking that SQL statement for a regular sentence.  The same applies when embedding SQL as a string in languages like Java and C#.&lt;/p&gt;

&lt;p&gt;It makes sense to use upper case for small embedded strings.  But SQL doesn’t need to be relegated to that role.  If you’re a database programmer then SQL should be your main language.  Your SQL should look good in isolation.  No other modern language uses upper case, using upper case for PL/SQL programs makes them look old fashioned.&lt;/p&gt;

&lt;h2 id=&quot;style-matters&quot;&gt;Style matters&lt;/h2&gt;

&lt;p&gt;Code that looks good will be respected more, maintained better, and is more likely to be reused.  I think most good programmers appreciate beautiful code and enjoy working on things that look good.&lt;/p&gt;

&lt;p&gt;There’s more than one way to do it and no one should look down on code just because it uses upper case, or spaces instead of tabs.  The important thing is that database programmesr ask themselves, “why am I writing code like this?”  Most SQL code is optimized to save bytes and adhere to tradition.&lt;/p&gt;

&lt;p&gt;Code should be optimized for the most important resource - our attention.  Spend extra time to write code that is easier to read.&lt;/p&gt;</content><author><name></name></author><summary type="html">Use these slightly unusual styles to reduce the complexity of SQL code:</summary></entry><entry><title type="html">Simplify string concatenation with alternative quotes and templates</title><link href="https://method5.github.io/Simplify-string-concatenation-with-alternative-quotes-and-templates/" rel="alternate" type="text/html" title="Simplify string concatenation with alternative quotes and templates" /><published>2017-05-12T00:00:00+00:00</published><updated>2017-05-12T00:00:00+00:00</updated><id>https://method5.github.io/Simplify-string-concatenation-with-alternative-quotes-and-templates</id><content type="html" xml:base="https://method5.github.io/Simplify-string-concatenation-with-alternative-quotes-and-templates/">&lt;p&gt;Combine the alternative quoting mechanism and templates to dramatically improve code readability compared to simple string concatenation.&lt;/p&gt;

&lt;h2 id=&quot;example&quot;&gt;Example&lt;/h2&gt;

&lt;p&gt;Here’s a simple example that uses the alternative quoting mechanism to avoid escaping single quotes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	execute immediate1 q'[ create database link ... using 'some_tns' ]';&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The alternative quoting mechanism allows almost any character to become the quote.  And the characters &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{,[,(,&amp;lt;&lt;/code&gt; are matched to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;},],),&amp;gt;&lt;/code&gt;.  This makes it much easier to embed code inside code - there’s no need to change all single quotation mark.&lt;/p&gt;

&lt;p&gt;Here’s a simple example of using a template for putting variables into a string:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	execute immediate replace(q'[
		create database link using '#TNS#'
	]', '#TNS#', v_tns);&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;There are template engines but a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;replace&lt;/code&gt; function works well enough.  This style allows keeping the dynamic code simple and as true to the real value as possible.  Dynamic code is complicated, adding a bunch of concatenation makes it even more complicated.&lt;/p&gt;

&lt;p&gt;Here’s the concatenation version:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-plaintext&quot; data-lang=&quot;plaintext&quot;&gt;	execute immediate 'create database link ... using '''||v_tns||'''';&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The concatenation version has less characters but the single quotes are ugly and confusing.  And this is the simplest possible example, it only gets worse.&lt;/p&gt;

&lt;p&gt;For a more realistic example, take a look at &lt;a href=&quot;https://github.com/method5/method5/blob/master/code/m5_pkg.pck#L172&quot;&gt;this SQL template&lt;/a&gt; in Method5.  It’s code that runs code, that runs code, that runs code.  It’s rare to nest dynamic code this many levels deep but sometimes it’s necessary.  The code is confusing enough with templates and alternative quotes.  Imagine what it would look like with hundreds of extra single quotes.&lt;/p&gt;

&lt;p&gt;The alternative quoting mechanism and templating makes it possible to embed code inside code, even multiple levels deep, and keep the code sane.&lt;/p&gt;

&lt;h2 id=&quot;why-not-use-other-features&quot;&gt;Why Not Use Other Features?&lt;/h2&gt;

&lt;p&gt;You may be thinking, “don’t use dynamic code”.  Features like reflection and polymorphism work great in most languages and can eliminate the need for dynamic code.&lt;/p&gt;

&lt;p&gt;Unfortunately those features don’t work well in PL/SQL.  The top Google result for “PL/SQL Reflection” is one of my Stackoverflow answers.  I’m not bragging - that doesn’t prove I’m an expert in PL/SQL reflection, it proves that there are no experts in PL/SQL reflection.  (Don’t bother Googling that answer - the result is ugly and almost certainly not helpful.)&lt;/p&gt;

&lt;p&gt;Luckily Oracle does a good job with dynamic SQL and PL/SQL.  It’s fast and convenient and improves with every release.  You don’t want to build overly generic code in PL/SQL.  It’s better to write code that builds specific code.&lt;/p&gt;

&lt;h2 id=&quot;make-the-code-readable&quot;&gt;Make the Code Readable&lt;/h2&gt;

&lt;p&gt;It’s easy to over-look the human side of code and ignore readability.  The program only works if the compiler is happy.  And the compiler doesn’t care if it looks bad.&lt;/p&gt;

&lt;p&gt;But the real user of all code is other programmers, not the compiler.  Dynamic SQL and PL/SQL are powerful but they are also confusing and require extra care.  Use templates, the alternative quoting mechanism, comments, and pay extra attention to formatting to make that code as beautiful as possible.&lt;/p&gt;

&lt;p&gt;If it looks right it will run right.&lt;/p&gt;</content><author><name></name></author><summary type="html">Combine the alternative quoting mechanism and templates to dramatically improve code readability compared to simple string concatenation.</summary></entry><entry><title type="html">Avoid Java in Oracle Database</title><link href="https://method5.github.io/Avoid-Java-In-DB/" rel="alternate" type="text/html" title="Avoid Java in Oracle Database" /><published>2017-04-12T00:00:00+00:00</published><updated>2017-04-12T00:00:00+00:00</updated><id>https://method5.github.io/Avoid-Java-In-DB</id><content type="html" xml:base="https://method5.github.io/Avoid-Java-In-DB/">&lt;p&gt;The primary languages of Oracle databases are SQL and PL/SQL.  Despite what many official sources claim, Java in the database is a distant third and should be avoided when possible.&lt;/p&gt;

&lt;p&gt;This is not a Java rant and I am not trying to say anything negative about Java as a programming language.  Obviously it’s a popular and good choice for working with databases.  Regardless of how good and popular Java is, there are several reasons to avoid using Java stored procedures &lt;em&gt;inside&lt;/em&gt; an Oracle database.&lt;/p&gt;

&lt;h2 id=&quot;java-is-not-always-available&quot;&gt;Java is Not Always Available&lt;/h2&gt;

&lt;p&gt;The main problem with using Java inside an Oracle database is that Java is not always available.  Oracle owns Java and has been advertising Java-in-the-database for decades, but in practice you cannot rely on it being installed.&lt;/p&gt;

&lt;p&gt;Java is not available for the Express Edition.  I’m not a big fan of Express Edition, but a lot of people use it, so this is a show-stopper for many products.&lt;/p&gt;

&lt;p&gt;Java is an optional component in all other editions.  It may be a default, but a lot of DBAs like to remove it because it makes upgrades slower.  Installing components is not a trivial task.  It often requires a DBA and downtime, and in many organizations that would require a lot of paperwork and justification.&lt;/p&gt;

&lt;h2 id=&quot;java-does-not-fit-perfectly&quot;&gt;Java Does Not Fit Perfectly&lt;/h2&gt;

&lt;p&gt;It’s unfair to fault a product for not integrating perfectly.  But when SQL and PL/SQL integrate so seamlessly, it’s hard not to look at Java stored procedures with disgust.&lt;/p&gt;

&lt;p&gt;Of course the types don’t completely match.  There’s probably all kinds of fun issues with string sizes, character sets, numeric precision, etc.&lt;/p&gt;

&lt;p&gt;Java objects can be larger than 30 characters longs, which causes some interesting naming problems.   (Although that problem may be fixed in 12.2 with larger names.).  The objects look different in the data dictionary and virtually all DBA scripts will fail to properly handle Java objects.  This can be fixed by translating the names with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DBMS_JAVA.LONGNAME&lt;/code&gt; but it’s a pain.&lt;/p&gt;

&lt;p&gt;There’s a culture clash between Java and database programmers.  Database programmers want code to “live” in the database, everyone else in the world wants code to “live” in version-controlled text files.  99% of all database programmers are clearly, horribly wrong here.  But you can’t convince them (believe me, I’ve tried), and they “own” the database.&lt;/p&gt;

&lt;p&gt;Some of these issues may not apply to &lt;a href=&quot;https://en.wikipedia.org/wiki/SQLJ&quot;&gt;SQLJ&lt;/a&gt;.  SQLJ seems like a neat way to integrate Java and SQL to me, but I’m in a small minority there.  I get the feelings that embedding SQL died in the 90s and nobody wants that kind of product anymore.&lt;/p&gt;

&lt;h2 id=&quot;sql-and-plsql-are-almost-always-better-choices&quot;&gt;SQL and PL/SQL are Almost Always Better Choices&lt;/h2&gt;

&lt;p&gt;If you’re doing something inside a database then SQL is almost always the best language.  Most people are only familiar with the basics, for running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;select * from employee;&lt;/code&gt;.  But Oracle’s SQL syntax is incredibly rich, there’s hardly any programming task that can’t be handled well with SQL.&lt;/p&gt;

&lt;p&gt;I’ve been hired a few times as a “PL/SQL Developer”.  What that title really means is that I wrote SQL and tied it together with PL/SQL.&lt;/p&gt;

&lt;p&gt;Yes, Java has more powerful language features than PL/SQL.  But they are completely irrelevant 99% of the time.  A good Oracle database program will do almost all of the heavy lifting in SQL.  The procedure language just needs to tie it together.  So PL/SQL’s improved integration features more than make up for being a less powerful language.&lt;/p&gt;

&lt;h2 id=&quot;this-is-a-shame&quot;&gt;This is a Shame&lt;/h2&gt;

&lt;p&gt;Oracle is missing a huge opportunity here.  It would be so easy to fix - just make Java a required component in all editions!&lt;/p&gt;

&lt;p&gt;Until that gets fixed that means you almost certainly should not develop a product with Java inside the database.  This is a shame because there are at least a few cases where it would be &lt;em&gt;incredibly&lt;/em&gt; useful to call Java from the database.&lt;/p&gt;

&lt;p&gt;I would love to be able to reliably take advantage of Java’s advantages:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;A more powerful development kit that helps for many tasks, like creating GUIDs, file processing, etc.&lt;/li&gt;
  &lt;li&gt;Run existing Java programs, like ANTLR.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the foreseeable future it’s best to do all database processing in SQL and PL/SQL, even if those languages don’t seem like a perfect fit for the task.&lt;/p&gt;</content><author><name></name></author><summary type="html">The primary languages of Oracle databases are SQL and PL/SQL. Despite what many official sources claim, Java in the database is a distant third and should be avoided when possible.</summary></entry></feed>