Feed aggregator

Striim MDR on PostgreSQL: Fixing striimsecuritytable does not exist

DBASolved - Fri, 2026-10-16 16:31

Striim won’t start on a new PostgreSQL MDR? If postgres owns the striim schema, here’s how to find it and fix the issue.

The post Striim MDR on PostgreSQL: Fixing striimsecuritytable does not exist appeared first on DBASolved.

Categories: DBA Blogs

Joel Kallman Day 2026 : It’s a Wrap! (#JoelKallmanDay)

Tim Hall - Thu, 2026-10-15 02:05

Yesterday was an Oracle community day called the Joel Kallman Day (#JoelKallmanDay) 2026. I would like to say a big thank you to everyone who took the time to join in. Here is the list of posts I saw. If I missed you out, give me a shout and I’ll add you.  Thanks to everyone who … Continue reading "Joel Kallman Day 2026 : It’s a Wrap! (#JoelKallmanDay)"

The post Joel Kallman Day 2026 : It’s a Wrap! (#JoelKallmanDay) first appeared on The ORACLE-BASE Blog.Joel Kallman Day 2026 : It’s a Wrap! (#JoelKallmanDay) was first posted on October 15, 2026 at 8:05 am.
©2024 "The ORACLE-BASE Blog". Use of this feed is for personal non-commercial use only. If you are not reading this article in your feed reader, then the site is guilty of copyright infringement. Please contact me at timseanhall@gmail.com

A Practical Guide to Oracle Regex

Pakistan's First Oracle Blog - Wed, 2026-10-14 20:29
icon), then paste everything below this comment.-->

If you've ever pulled thousands of rows into an application just to check whether a product code looks right, this post is for you. Oracle's built-in regular expression functions let you validate, search and tidy text right where the data lives, so you don't need extra string-handling code in every app that touches the table.


The toolkit in one glance

Oracle gives you one condition and four functions:

Name What you get back REGEXP_LIKEA true/false test, used in WHERE clauses and constraints REGEXP_COUNTHow many times a pattern shows up REGEXP_INSTRThe position where a match starts (or ends) REGEXP_SUBSTRThe matching text itself REGEXP_REPLACEThe string with matches swapped for something else

Each accepts an optional match-parameter string. The useful flags are i (ignore case), c (respect case), n (let the dot match a newline), m (treat each line as its own line for anchors) and x (ignore spaces in the pattern).

Setting up the sample data
CREATE TABLE stock_items (
  sku            VARCHAR2(20),
  item_desc      VARCHAR2(100),
  supplier_email VARCHAR2(80),
  delivery_date  VARCHAR2(10),
  handling_note  VARCHAR2(200)
);

INSERT INTO stock_items VALUES
 ('BRK-0215',  '  Heavy duty   brake rotor 330mm ', 'accounts@brakeworks.example.com.au', '07/03/2026',
  '<note>fragile</note><note>keep dry</note>');
INSERT INTO stock_items VALUES
 ('ROT-1180B', 'Rotor rotor bolt kit',  'sales@boltbarn.example.com.au', '19/11/2026',
  '<note>pallet only</note>');
COMMIT;
1. Guarding the door with a CHECK constraint

Say every SKU must be three capital letters, a hyphen, four digits, and optionally one trailing capital letter. One constraint handles it for every application:

ALTER TABLE stock_items ADD CONSTRAINT ck_sku_shape
  CHECK (REGEXP_LIKE(sku, '^[A-Z]{3}-[0-9]{4}[A-Z]?$', 'c'));

The anchors ^ and $ force the whole value to fit the pattern, and the c flag keeps lowercase letters out. Results:

BRK-0215    accepted
ROT-1180B   accepted
brk-0215    rejected (lowercase)
BRK0215     rejected (no hyphen)
BRK-215     rejected (only three digits)
BRK-0215BB  rejected (two trailing letters)
2. Counting words
SELECT item_desc,
       REGEXP_COUNT(item_desc, '\w+') AS word_count
FROM   stock_items;

For 'Rotor rotor bolt kit' this returns 4. It's a quick way to flag descriptions that are too short to be useful.

3. Pulling out a piece of text

To get each supplier's domain, capture it in a group and ask for that group with the sixth argument:

SELECT REGEXP_SUBSTR(supplier_email, '@(\S+)$', 1, 1, NULL, 1) AS supplier_domain
FROM   stock_items;
brakeworks.example.com.au
boltbarn.example.com.au

The @ is matched but left out of the result, because only the bracketed group is returned.

4. Finding where something sits
SELECT REGEXP_INSTR('Rotor kit 330mm', '\d')           AS first_digit,
       REGEXP_INSTR('Rotor kit 330mm', '\d+', 1, 1, 1) AS just_after_number
FROM   dual;
FIRST_DIGIT  JUST_AFTER_NUMBER
-----------  -----------------
         11                 14

The fifth argument, 1, asks for the position immediately after the match instead of its start.

5. Cleaning up messy whitespace

Our first row has leading, trailing and doubled spaces:

SELECT REGEXP_REPLACE(TRIM(item_desc), '\s{2,}', ' ') AS tidy_desc
FROM   stock_items;

' Heavy duty brake rotor 330mm ' becomes 'Heavy duty brake rotor 330mm'. Any run of two or more whitespace characters collapses into one space.

6. Back references: reshuffling and spotting repeats

A back reference lets you reuse what a group captured. Here we convert Australian-style dates (DD/MM/YYYY) to ISO format:

SELECT delivery_date,
       REGEXP_REPLACE(delivery_date,
                      '^(\d{2})/(\d{2})/(\d{4})$',
                      '\3-\2-\1') AS iso_date
FROM   stock_items;
07/03/2026   2026-03-07
19/11/2026   2026-11-19

Rows that don't fit the pattern pass through unchanged, so test for that before trusting the output.

Back references also catch accidental repeats, such as "Rotor rotor":

SELECT sku
FROM   stock_items
WHERE  REGEXP_LIKE(item_desc, '(^| )(\w+) \2( |$)', 'i');

Group 2 captures a word, and \2 demands the same word straight after it. This flags ROT-1180B.

7. Greedy versus lazy matching

By default, quantifiers grab as much as they can. Adding ? makes them take as little as possible:

SELECT REGEXP_SUBSTR(handling_note, '<note>.*</note>')  AS greedy,
       REGEXP_SUBSTR(handling_note, '<note>.*?</note>') AS lazy
FROM   stock_items
WHERE  sku = 'BRK-0215';
GREEDY                                          LAZY
----------------------------------------------  ---------------------
<note>fragile</note><note>keep dry</note>      <note>fragile</note>

Greedy runs to the last closing tag, while lazy stops at the first.

Gotchas worth remembering
  • Character classes need two sets of brackets. Write [[:upper:]]+, not [:upper:]+. The inner pair names the class and the outer pair makes it a list.
  • Don't assume Perl, Python or JavaScript syntax carries over. Oracle supports shortcuts like \d, \w and \s, but not word-boundary markers (\b) or lookaheads.
  • Escape literal metacharacters. To match a real dot or bracket, use \. or \(.
  • Mind performance. A regex condition on a large column usually can't use an ordinary index. If a pattern query is hot, consider a function-based index or a cheaper pre-filter such as LIKE.
  • Multibyte text works, but write characters directly. Oracle matches on encoded bytes rather than \uXXXX escapes.
Wrapping up

Start with a constraint on your messiest column, since that's where the payoff is quickest. Then add REGEXP_SUBSTR and REGEXP_REPLACE to your reporting queries. Once you've written a few patterns, you'll find a lot of application-side string handling can simply be deleted.

Categories: DBA Blogs

Who owns the information? Data ownership and stewardship in an ECM

Yann Neuhaus - Wed, 2026-10-14 06:50

I often see this pattern in organizations. The ECM project was an overall success: the migration is complete, and users are happy with the new solution. But after a year or two, the magic faded. Search results are cluttered with duplicates, metadata is inconsistent, permissions have drifted, and nobody dares to delete anything. Some users have gone back to using shared drives.

The platform itself is not the cause; it simply does what it was configured to do. The real problem is that nobody was ever clearly responsible for the information. The project had a sponsor, a manager and a budget. The information had none of these.

Alone, like unmanaged information

I touched on this topic briefly in previous posts (Why ECM Projects fail or Information debt), but let’s take a closer look.

The question remains unanswered

Because it is organizational and political rather than technical, it feels more challenging than a workshop on vault structure. It also seems to be something for ‘phase two’, which rarely receives the same level of attention. Business users assume IT handles it, and IT assumes the business does. Furthermore, ‘ownership’ can mean different things to different people, such as who created the document, who is accountable for it, who can edit it and who decides when it should be deleted.

Four different roles

I think we should start by defining the four crucial roles.

  • Data owner is a business role that is accountable for a category of information. For example, the HR director is responsible for personnel files. The owner decides on the rules for classification, retention and access.
  • Data steward ensures that these rules are followed on a daily basis. They monitor metadata quality, handle exceptions and propose improvements. This is the role that is most often missing.
  • Custodian is usually IT. They keep the platform secure, backed up and running, but they should not decide what the information means or how long it is kept.
  • Contributors are users who create and edit content. Being the author of a document does not make you the owner of its information.

In short: owners decide, stewards organize, custodians protect, users contribute.

When one of these is missing, the others compensate badly. IT ends up making business decisions, or users end up inventing their own conventions.

Why it matters even more in M-Files

M-Files organizes information based on its metadata, not its storage location. The metadata model is a shared contract, and every contract needs someone to take responsibility for it.

  • Who approves new classes or values in a value list? Without a clear answer, terms such as ‘Contract’, ‘Contracts’ and ‘Agreement’ end up coexisting.
  • Who decides which properties are mandatory?
  • Who in the business owns each workflow, since only they know when the process changes?
  • Who reviews permissions as people and organizations change?
  • Who validates retention and destruction rules?

AI adds urgency. Whether you use M-Files Aino or another AI capability, the quality of the answers depends on the content: accurate metadata, no duplicates and no obsolete documents being passed off as current. AI does not fix a governance gap, it exposes it.

Making ownership explicit

I recommend the following six best practices. You should use them in any ECM solution.

  • Ask early and write it down. For each information domain, name the owner, the steward(s), the custodian and the applicable rules. A simple table validated by management is enough.
  • Name roles, not just people, with a deputy, so the organization survives a departure or reorganization.
  • Give stewards time and tools. Use M-Files views that surface missing metadata, notifications and dashboards to make the work lighter.
  • Define a light change process for the metadata model, such as a monthly review between steward and administrator.
  • Schedule reviews: quarterly on data quality, twice a year on permissions, yearly on retention and the model itself.
  • Hand over governance at go-live, not just a configured vault: the roles, the decisions and the reasons behind them.
Do a quick assessment

If you want to evaluate where you are with your solution, try to answer the following questions:

  • Can you name the person accountable for each type of document?
  • Who can approve a new document class?
  • Who decides when a document can be deleted?
  • When did the business last review access to sensitive information?
  • If your ECM administrator left tomorrow, would the rules still be understood?

Expert level: Who are the deputies?

If you answered ‘I don’t know’ or ‘I’m uncertain’ to at least one question, then you have identified a risk before it becomes a failed project.

Information needs an owner

Successful ECM projects are rarely lost on technology. They are lost slowly, in the months after go-live, through a lack of clear responsibility. The platform keeps working while the information quietly loses its value.

The fix is not complicated, but it does require a decision: information needs owners, just like budgets and projects do. Asking ‘Who owns the information?’ early, and writing down the answer, is one of the cheapest and most effective investments you can make in an ECM.

If you are planning a project, or wondering why a past one is not delivering what it promised, this is a good question to start with. And if you would like to discuss how to set up ownership and stewardship in your own M-Files environment, feel free to reach out.

L’article Who owns the information? Data ownership and stewardship in an ECM est apparu en premier sur dbi Blog.

RAG Time with APEX for #JoelKallmanDay

Flavio Casetta - Wed, 2026-10-14 03:16

What is the best approach when it comes to execute a semantic search for RAG (Retrieval Augmented Generation) in OllAPEX ?

OllAPEX is an Oracle APEX workbench designed for local LLM integration via Ollama, with semantic search over documents (such as Oracle skills repositories or excerpts from Oracle documentation) amongst other functions.

The main purpose of semantic search report applied to the Oracle Skills or other Oracle documents is to test a search before implementing a RAG mechanism inside OllAPEX itself. 

The Real-World Context: Semantic Search in OllAPEX

In OllAPEX, semantic search allows users to query vector-embedded markdown files directly from an APEX interface.

               [ User Input Topic / Query ]
                           │
                           ▼
          ollapex.semantic_search(:TOPIC, ...)
                           │
                           ▼
          JSON_TABLE (Extract Top N Chunks)
                           │
                           ▼
    Join with OLLAPI_DOCUMENT_CHUNKS & UPLOADS
                           │
                           ▼
           [ Render Results in a report  ]  

The underlying SQL query calls a PL/SQL vector search function ollapex.semantic_search(), parses the returning JSON payload via JSON_TABLE, and joins the parsed rows with document chunk metadata tables (ollapi_document_chunks and ollapi_uploads_for_embedding). Here is the user-facing application displaying semantic search results for queries over chunks of Oracle skills in markdown format: 

picture #1, semantic search report

The natural execution:

The initial version of the query behind the report looked like this:

picture 2, semantic search query
And its execution plan:

picture 3, execution plan for the initial semantic search query
Then I thought: how can I ensure that the CTE is executed only once as I don't want that the prompt embedding function is called more times than necessary ?

The wannabe "optimized" query: forcing MATERIALIZE 

To ensure the vector search function in the CTE executes only once, I added a /*+ MATERIALIZE */ hint:

picture 4, query with MATERIALIZE hint added
And this is the execution plan that I got: 

picture 5, execution plan for the semantic search query with MATERIALIZE

As you see the cost is slightly increased and now there is a FULL scan on the temporary table created by the MATERIALIZE hint. No big deal but it doesn't look like an improvement to me.

But wait, is this the best way to tackle this problem?

The good old mantra: keep it easy!

In the end if I want to be sure that the embedding function is executed only once and there are no dependencies from what follows, then I am better off separating the embedding phase from the search phase:

dynamic action doing the embedding before running the report

So when the user clicks on the search button, a dynamic action performs the embedding on user's prompt and returns the results as a JSON array (CLOB).

The final query eventually uses the vector to perform the semantic search:

final semantic search query 

Since there are no vector indexes defined (yet), the execution plan remains identical to that of picture 3, thus performing a so-called "exact" similarity search but now I am 100% sure that the embedding request will be performed just once.

Have a nice #JoelKallmanDay, remembering Joel, Scott and Carl. 

Categories: DBA Blogs

Continuous Delivery of Oracle Database Features #JoelKallmanDay

Tim Hall - Wed, 2026-10-14 01:38

As my entry for #JoelKallmanDay 2026, I thought I would write about the continuous delivery of Oracle database features. Quick history lesson In the past there used to be quite a slow release cycle for the database. It varied a lot over the years, but it moved towards a first and second release of each … Continue reading "Continuous Delivery of Oracle Database Features #JoelKallmanDay"

The post Continuous Delivery of Oracle Database Features #JoelKallmanDay first appeared on The ORACLE-BASE Blog.Continuous Delivery of Oracle Database Features #JoelKallmanDay was first posted on October 14, 2026 at 7:38 am.
©2024 "The ORACLE-BASE Blog". Use of this feed is for personal non-commercial use only. If you are not reading this article in your feed reader, then the site is guilty of copyright infringement. Please contact me at timseanhall@gmail.com

Sawn-off by SQL*Plus – how to prevent it rounding long numeric values #JoelKallmanDay

The Anti-Kyte - Wed, 2026-10-14 01:30

Whenever I need to generate a CSV in a batch routine, I turn to good old SQL*Plus. However, when testing such a routine recently, I came across a behavioural quirk which left me a bit stumped. Hopefully, what follows will help others avoid falling down the rabbit hole I found myself in when trying to figure out just what was happening…

TL;DR

If you’ve hit this bug and landed here desparately seeking a solution then you’re probably not in the mood for the ramble that follows, so *spoiler alert* – the cluprit is the numwidth SQL*Plus environment variable, which is set to 10 by default. Any number that is longer than 10 characters (including any decimal point) will get rounded.

The solution is to set this variable to a higher value ( it goes up to 128).

If you’ve a bit more time on your hands and would like to know the gory details, read on…

Read more: Sawn-off by SQL*Plus – how to prevent it rounding long numeric values #JoelKallmanDay Enviornment

The following examples have been run on Oracle 19c Enterprise Edition running on Oracle Linux. The SQL*Plus version is 19.3.

Fun with Numbers

Let’s look at a very simple query which just returns some numeric values

with cash as
(
select 1 as id, 1 as amount from dual union all
select 2 as id, 12 as amount from dual union all
select 3 as id, 123 as amount from dual union all
select 4 as id, 1234 as amount from dual union all
select 5 as id, 12345 as amount from dual union all
select 6 as id, 123456 as amount from dual union all
select 7 as id, 1234567 as amount from dual union all
select 8 as id, 12345678 as amount from dual union all
select 9 as id, 123456789 as amount from dual union all
select 10 as id, 1234567890 as amount from dual union all
select 11 as id, 1234567.24 as amount from dual
)
select id, amount
from cash
order by id
/

Yes, I know I don’t need to repeat the column aliases on every line of the with query but it does help to line up the values nicely (more-or-less).
Anyhow, run this and we get :

So far, so normal. But notice what happens if we use longer values…

with cash as
(
select 1 as id, 12345678.41 as amount from dual union all
select 2 as id, 123456789.15 as amount from dual union all
select 3 as id, 1234567890.87 as amount from dual
)
select id, amount,
to_char(amount) as actual_value_string
from cash
order by id
/
	ID     AMOUNT ACTUAL_VALUE_STRING
---------- ---------- ----------------------------------
1 12345678.4 12345678.41
2 123456789 123456789.15
3 1234567891 1234567890.87


So the amount values are now rounded (aka WRONG !).
To understand why this might be happening, let’s combine our queries and show the lengths of each value :

with cash as
(
select 1 as id, 1 as amount from dual union all
select 2 as id, 12 as amount from dual union all
select 3 as id, 123 as amount from dual union all
select 4 as id, 1234 as amount from dual union all
select 5 as id, 12345 as amount from dual union all
select 6 as id, 123456 as amount from dual union all
select 7 as id, 1234567 as amount from dual union all
select 8 as id, 12345678 as amount from dual union all
select 9 as id, 123456789 as amount from dual union all
select 10 as id, 1234567890 as amount from dual union all
select 11 as id, 1234567.24 as amount from dual union all
select 12 as id, 12345678.41 as amount from dual union all
select 13 as id, 123456789.15 as amount from dual union all
select 14 as id, 1234567890.87 as amount from dual
)
select id, amount, length(amount) as amount_length
from cash
order by id
/
	ID     AMOUNT AMOUNT_LENGTH
---------- ---------- -------------
1 1 1
2 12 2
3 123 3
4 1234 4
5 12345 5
6 123456 6
7 1234567 7
8 2345678 8
9 123456789 9
10 1234567890 10
11 1234567.24 10
12 12345678.4 11
13 123456789 12
14 1234567891 13

It looks like anything longer than 10 characters (including the decimal point) is getting rounded.
It turns out, the culprit is this innocent-looking SQL*Plus environment setting :

show numwidth
numwidth 10

The 19c Documentation says that numwidth defines “the default width for displaying numbers.”

It goes on to say that

“COLUMN FORMAT settings take precedence over SET NUMFORMAT settings, which take precedence over SET NUMWIDTH settings.”

What is doesn’t say is what the value range is, so let’s experiment.
First of all, let’s see if you can turn it off, as you can with some other SQL*Plus environment settings, by setting it to 0 :

set numwidth 0
SQL> set numwidth 0
SP2-0267: numwidth option 0 out of range (2 through 128)

OK, let’s set it to it’s maximum value then :

set numwidth 128

Initially, this seems to work fine, but if you then try to run a query returning any numeric value you run into problems :

SQL> select 1 from dual;
SP2-0253: data item 1 ("1") will not fit on line
SQL>

This is because we still have the linesize variable set to it’s default value :

SQL> show lines
linesize 80

Setting it to something larger than 128 solves the problem :

set lines 130
select 1 from dual;

Fortunately for me, this does not mean that there is suddenly lots of leading spaces for numeric values if I’m generating csv output :

set markup csv on delimiter , quote on
with cash as
(
select 1 as id, 1 as amount from dual union all
select 2 as id, 12 as amount from dual union all
select 3 as id, 123 as amount from dual union all
select 4 as id, 1234 as amount from dual union all
select 5 as id, 12345 as amount from dual union all
select 6 as id, 123456 as amount from dual union all
select 7 as id, 1234567 as amount from dual union all
select 8 as id, 12345678 as amount from dual union all
select 9 as id, 123456789 as amount from dual union all
select 10 as id, 1234567890 as amount from dual union all
select 11 as id, 1234567.24 as amount from dual union all
select 12 as id, 12345678.41 as amount from dual union all
select 13 as id, 123456789.15 as amount from dual union all
select 14 as id, 1234567890.87 as amount from dual
)
select id, amount, length(amount) as amount_length
from cash
order by id
/

Another point to note is that the linesize error only appears to be triggered when you’re outputting to the screen. Obviously, this is not the case in a batch job generating a CSV file.

Using a settings script for CSVs

Rather than having to remember to set numwidth to an appropriate value for all of my CSV generating scripts, I think I’ll just use a settings script ( csv_settings.sql ):

set feedback off
set echo off
set termout off
set markup csv on delimiter , quote on
set numwidth 128

Then I can just call it as part of my csv scripts :

@csv_settings.sql
spool cash.csv
with cash as
(
select 1 as id, 1 as amount from dual union all
select 2 as id, 12 as amount from dual union all
select 3 as id, 123 as amount from dual union all
select 4 as id, 1234 as amount from dual union all
select 5 as id, 12345 as amount from dual union all
select 6 as id, 123456 as amount from dual union all
select 7 as id, 1234567 as amount from dual union all
select 8 as id, 12345678 as amount from dual union all
select 9 as id, 123456789 as amount from dual union all
select 10 as id, 1234567890 as amount from dual union all
select 11 as id, 1234567.24 as amount from dual union all
select 12 as id, 12345678.41 as amount from dual union all
select 13 as id, 123456789.15 as amount from dual union all
select 14 as id, 1234567890.87 as amount from dual
)
select id, amount, length(amount) as amount_length
from cash
order by id
/
spool off
Joel Kallman Day

If you want to know more about Joel Kallman Day then – as with so much else in the Oracle world – Oracle Base is probably a good place to start.

Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance

Yann Neuhaus - Mon, 2026-10-12 02:22

With SQL Server 2025, Microsoft lets the database engine call an AI model by itself. sp_invoke_external_rest_endpoint sends an HTTPS request straight from T-SQL, to Azure OpenAI or to any other REST service, so an embedding or a completion no longer needs application code in between.

But what happens under heavy pressure, when hundreds of sessions make that call at the same moment and the model takes its time to answer? I ran this scenario on SQL Server 2025 and on Azure SQL Database, with the same procedure and the same load script. The two platforms do not react the same way at all.

100 sessions calling a 30-second endpointSQL Server 2025Azure SQL Database, 2 vCoresSQL Server 2025 with Resource GovernorCalls sent to the endpoint at once1002222What happens to the othersnothing holds them backrefused at once, error 10928queued, all served after 150 sWorker threads held10022100

The documentation of the procedure describes a cap at 10% of the worker threads. That is not what I measured. Azure SQL Database does cap the calls in my tests, but at 15% of its workers: 22 calls at 2 vCores, 45 at 4 vCores, 30 on a Standard S3. SQL Server 2025 has no cap at all, and the rest of this post shows what happens without it.

The lab

The on-premises setup has three parts, all on one virtual machine (Windows Server 2022, 2 vCPUs): a load generator, a SQL Server 2025 Standard instance, and a small HTTPS endpoint that answers after the delay given in the URL.

The call is wrapped in a procedure, so that every session runs exactly the same thing:

CREATE OR ALTER PROCEDURE dbo.CallSlowAi @delay int, @timeout smallint = 230
AS
BEGIN
    DECLARE @url nvarchar(400) = CONCAT(N'https://<YOUR_VM>:8443/?delay=', @delay);
    DECLARE @ret int, @resp nvarchar(max);
    EXEC @ret = sp_invoke_external_rest_endpoint @url = @url, @method = 'POST',
         @payload = N'{"input":"hello"}', @timeout = @timeout, @response = @resp OUTPUT;
    RETURN @ret;
END

The load generator is a PowerShell function that opens N connections without pooling, sends EXEC dbo.CallSlowAi @delay = 30 on all of them at the same moment, and records for each session the elapsed time and the error number. One process, so the client itself does not slow the VM down.

Before measuring SQL Server, I called the endpoint directly with 200 parallel requests: they all came back in 30.6 seconds. The endpoint is not the bottleneck.

On-premises: no limit, until the workers run out

A worker thread is what SQL Server uses to execute a request: one request running, at least one worker busy. The instance has a fixed pool of them, set by max worker threads; with the default setting on this 2-vCPU machine, that is 512. When they are all taken, new work waits with the THREADPOOL wait type, and that includes logging in, because a login needs a worker too (see my previous blog about this wait type).

Three words matter here, and their numbers should not be added together. A session is a connection. When it runs a request, the request is split into one or more tasks, and each task needs a worker thread to run. A simple call like ours is one task, so one worker; a parallel query would take several. The worker counts I quote also include SQL Server’s own background tasks: about 45 workers on this idle instance. A wait type, on the other hand, is counted per task, whoever owns it.

A session waiting for the endpoint reports the HTTP_EXTERNAL_CONNECTION wait type and keeps its worker thread for the whole wait: every waiting call added one worker to that baseline.

With 300 sessions, SQL Server sent everything at once. I counted 300 TCP connections from sqlservr.exe to port 8443, and all calls returned together:

ErrorNumber : 0
Sessions    : 300
MinSec      : 30.2
MaxSec      : 34.5

With 600 sessions, the instance has only 512 worker threads to give. 510 connections were open at the same time, and the calls finished in two groups:

Finished after (s)   Sessions
30                   193
40                   316
50                     1
60                    90

The first 509 calls left immediately, one per available worker. The last 91 did not wait for the endpoint: they waited for a worker. No error was raised at any point, and nothing held the calls back.

What the rest of the instance sees

I measured the saturation itself during an earlier run of the same 600 sessions, with HTTP/2 still enabled on the endpoint (see below). From the dedicated admin connection:

active_workers  queued_tasks
556             154

-------------------------------------

wait_type                  n
HTTP_EXTERNAL_CONNECTION   513
THREADPOOL                 154

At that moment an ordinary sqlcmd connection failed:

Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : Login timeout expired.
Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : Unable to complete login process due to delay in prelogin response.

The admin connection kept answering, and the instance recovered by itself once the calls completed. KILL also works at once on a waiting session (error 596 on the client side).

HTTP/2 changes the shape, not the outcome

HTTP.sys, which hosts my test endpoint, offers HTTP/2 by default. In that mode SQL Server opened 6 TCP connections instead of one per call, and only 100 calls were in flight per host name. The same 300 sessions then finished in three waves:

Finished after (s)   Sessions
30                   100
60                   100
90                   100

The queued sessions show the same HTTP_EXTERNAL_CONNECTION wait and hold a worker while they queue, so the pool empties just as well: the 556 workers above were measured in this mode. The queue has a second effect. @timeout keeps running while a call waits its turn. With a 30-second endpoint and @timeout = 45, the first 100 calls succeeded and the 100 queued ones failed after 45.5 seconds with error 31629, The external rest endpoint execution exceeded the timeout value, although the endpoint was answering normally.

Turning HTTP/2 off on the endpoint removes that queue. I disabled it in HTTP.sys (EnableHttp2Tls and EnableHttp2Cleartext set to 0, then a reboot) and replayed the same load:

300 sessions, 30-second endpointHTTP/2HTTP/1.1TCP connections opened by SQL Server6300Calls in flight at once100300Last call returns after90 s34.5 s

The waves are gone and so are the timeouts caused by the queue. It is not a fix for the instance, though. Each call still holds a worker, the 600-session run at the top of this section was made in HTTP/1.1, and the endpoint now receives every call at once. With a real AI provider you also do not choose the protocol: the server does.

I did not capture the HTTP/2 negotiation, so I cannot say which side sets the figure of 100. What the two modes show together is that SQL Server applies no cap of its own.

But the documentation says 10%?

The page of the procedure is marked as applying to SQL Server 2025, Azure SQL Database, Azure SQL Managed Instance and SQL database in Microsoft Fabric. Its throttling section reads:

The number of concurrent connections to external endpoints done via sp_invoke_external_rest_endpoint are capped to 10% of worker threads, with a maximum of 150 workers.

It adds that a call made beyond the limit raises error 10928. With 512 worker threads, I expected about 51 calls to pass and the others to fail. I got neither the cap nor the error, on RTM as on CU9.

The next sentence of that section gives a hint: it speaks of a single database and of an elastic pool, two notions that only exist in Azure SQL Database. So I ran the same test there.

Azure SQL Database: 22 calls, then an error

Azure SQL Database only calls endpoints from a closed list of Azure services, so the slow endpoint becomes an Azure Function. The database is a single Azure SQL Database in Switzerland North. I started on the vCore model, General Purpose serverless on standard-series (Gen5) hardware with 2 vCores maximum, then scaled the same database to 4 vCores, and finally to Standard S3 in the DTU model. The function runs on the Consumption plan, Node.js 22, in the same region. The procedure is the same, with the URL of the function, and the load script only changes its connection string.

Before any load, the governance view of the database already shows a dedicated limit:

SELECT primary_group_max_workers, primary_group_max_outbound_connection_workers
FROM sys.dm_user_db_resource_governance;
primary_group_max_workers  primary_group_max_outbound_connection_workers
150                        22

I stated my bet before running the load: 22 successes, 78 errors. Result for 100 sessions calling a 30-second endpoint:

ErrorNumber  Sessions  Finished after (s)
0            22        30
10928        78        0
Resource ID : 4. The outbound connection worker limit for the database is 22 and has been reached.

The 78 rejected sessions got their answer immediately, which leaves the database 128 of its 150 workers for everything else, whatever the endpoint does.

Two remarks on this test. The ratio is 15%, not the documented 10%. At 2 vCores the database has 150 workers and a limit of 22. I scaled it to 4 vCores: 300 workers, a limit of 45, and the same load gave 45 successes and 55 errors. In the DTU model, a Standard S3 shows 200 workers and a limit of 30. This is one database, in one region, read on three service objectives and load-tested on two. The ratio could differ on other tiers, hardware generations or Hyperscale, and Microsoft may change it: treat 15% as what I observed, not as a rule. On the endpoint side I needed to do a small adjustment as well: an Azure Function on the Consumption plan served only 100 concurrent requests per instance until I raised maxConcurrentRequests in host.json. A direct test of 200 parallel requests took 62.8 seconds before the change and 30.4 after.

The same limit on-premises, with Resource Governor

SQL Server 2025 exposes nothing comparable. On CU9, sys.dm_user_db_resource_governance does not exist, no system column deals with outbound connections, and the only related configuration option is the on/off switch external rest endpoint enabled.

What SQL Server does have is Resource Governor, and a workload group can limit its number of concurrent requests. I created a group with the Azure value and sent the sessions of the load generator into it through their application name:

USE master;
GO
CREATE WORKLOAD GROUP AiCalls WITH (GROUP_MAX_REQUESTS = 22) USING [default];
GO
CREATE FUNCTION dbo.RgClassifier() RETURNS sysname WITH SCHEMABINDING
AS
BEGIN
    RETURN CASE WHEN APP_NAME() = N'AiLoad' THEN N'AiCalls' ELSE N'default' END;
END
GO
ALTER RESOURCE GOVERNOR WITH (CLASSIFIER_FUNCTION = dbo.RgClassifier);
ALTER RESOURCE GOVERNOR RECONFIGURE;

Same load as on Azure, 100 sessions calling a 30-second endpoint:

ErrorNumber  Sessions
0            100

Finished after (s)   Sessions
30                   22
60                   22
90                   22
120                  22
150                  12

The limit is applied to the unit: never more than 22 calls reach the endpoint. But there is no error. Every session ends up being served, and the last ones wait two minutes for it.

Where Resource Governor stops

During the second wave of that test, the group, the waits and the workers looked like this:

The 56 queued sessions wait on RESMGR_THROTTLED, and each of them has a worker. The instance counts 123 active workers against 45 at rest: 78 more, exactly the 22 calls in flight plus the 56 sessions in the queue.

Beyond the 22nd callAzure SQL DatabaseSQL Server 2025 with Resource GovernorWhat the session getserror 10928, immediatelya place in a queueWorker of that sessionreleasedheld until its turn comes and the call returnsCalls reaching the endpoint2222Worker poolprotectednot protected

Resource Governor protects the service being called. It does not protect the instance. With 600 sessions classified in that group, 22 calls would be in flight and the 578 others would still be queued, each holding a worker, against a pool of 512. I did not run that last case; it follows from the two measurements above.

What to take from this

On SQL Server 2025, every session waiting for an external endpoint holds a worker thread, and the engine sets no limit on how many can wait at once. Azure SQL Database does have such a cap, at 15% of its workers in my tests rather than the documented 10%, and a call beyond it is refused immediately. On-premises, a slow AI service plus a concurrent application is enough to exhaust the worker pool and to keep new connections out, with no blocking chain to look for and an error message, when there is one, that points at the endpoint.

The difference is also one of scope. In Azure SQL Database, the limit belongs to the database: a flood of slow calls is refused at the door of that database, and the 128 workers left keep it running. In SQL Server, the worker pool belongs to the instance. Every database on it shares the same 512 workers, so one application calling a slow AI service can lock out the users of all the others.

Resource Governor can cap the number of calls sent to the service, in Standard Edition too, but it queues the surplus instead of refusing it, and a queued session costs a worker. If you want the Azure behavior, the refusal has to come from the code that makes the call, or from the application in front of it. Make sure you can reach the dedicated admin connection before you need it: it works locally out of the box (sqlcmd -A), but from another machine it requires the remote admin connections option. It was the only way in during the saturation, and KILL on the waiting sessions frees their workers at once.

L’article Calling AI from SQL Server 2025 can lock everyone out of your on-prem instance est apparu en premier sur dbi Blog.

Removing instantiation filtering from a GoldenGate replicat

Yann Neuhaus - Mon, 2026-10-12 01:59

In a recent blog, I explained how instantiation filtering works. DBOPTIONS ENABLE_INSTANTIATION_FILTERING makes a replicat discard any record whose commit CSN is at or below a table’s instantiation CSN. It applies everything above it. This replicat parameter should be kept during the whole initial load process.

At some point the replicat has processed past the instantiation boundary for every table, and the filter has nothing left to do. Let’s answer the subsequent and very practical question: how to confirm, before editing the parameter file, that the replicat has cleared the boundary for every table it maps?

Which SCN should I check ?

To summarize what needs to be checked: it is safe to remove DBOPTIONS ENABLE_INSTANTIATION_FILTERING once the replicat last applied CSN is greater than the instantiation CSN of every table it maps.

To answer this question, you have two sources of information:

  • The per-table boundary, stored in dba_apply_instantiated_objects, with one row per source object.
  • The replicat last applied CSN, stored in the checkpoint table in the log_csn column.
SQL check

Read the boundaries first:

SELECT source_database, source_object_owner, source_object_name, instantiation_scn
FROM dba_apply_instantiated_objects
ORDER BY instantiation_scn DESC;
SOURCE_DATABASE  SOURCE_OBJECT_OWNER  SOURCE_OBJECT_NAME  INSTANTIATION_SCN
---------------- -------------------- ------------------- -----------------
PDB1             APP_PDB1             SALES               52642820
PDB1             APP_PDB1             ORDERS              52642649

Then read the replicat last applied CSN from its checkpoint table:

SELECT group_name, log_csn
FROM oggadmin.checkpoint
WHERE group_name = 'REP1';

You can safely remove ENABLE_INSTANTIATION_FILTERING when log_csn is greater than the highest instantiation_scn among the tables it maps. A one-shot verdict, scoped to a single source database:

SELECT 'REP1' AS group_name,
c.log_csn,
MAX(o.instantiation_scn) AS max_boundary,
CASE WHEN c.log_csn > MAX(o.instantiation_scn) THEN 'SAFE TO REMOVE' ELSE 'NOT YET' END AS verdict
FROM dba_apply_instantiated_objects o
LEFT JOIN oggadmin.checkpoint c ON c.group_name = 'REP1'
WHERE o.source_database = 'PDB1'
GROUP BY c.log_csn;

Before a replicat starts for the first time, log_csn is NULL and the verdict is NOT YET:

GROUP_NAME  LOG_CSN  MAX_BOUNDARY  VERDICT
----------- -------- ------------- -------
REP1                 52642820      NOT YET

A replicat may map more than one source database, or only a subset of the instantiated objects. Then narrow the join to the objects applied.

WARNING: A replicat that has never started has no checkpoint row at all, so log_csn returns nothing. Treat that as “not safe”: there is no applied position, so it cannot have cleared anything. The verdict query above handles this case. It starts from the instantiated objects and left joins the checkpoint table. A missing row gives a NULL log_csn, and the verdict falls to NOT YET instead of the query returning no row at all.

After some time, once the replicat catches up with the initial load, the same query returns:

GROUP_NAME  LOG_CSN   MAX_BOUNDARY  VERDICT
----------- --------- ------------- --------------
REP1        52643651  52642820      SAFE TO REMOVE

You can now cleanly delete the DBOPTIONS ENABLE_INSTANTIATION_FILTERING parameter and restart your replicat.

adminclient check

From the adminclient, INFO REPLICAT REP1, DETAIL reports the applied CSN without using sqlplus:

OGG> INFO REPLICAT REP1, DETAIL
...
Last Committed Transaction CSN value: 52643651

Compare that number against the instantiation_scn from the view exactly as above.

REST API check

The CSN is reachable over the REST API, just not from a GET endpoint. You need to execute a command against the replicat using the POST /services/{version}/replicats/{replicat}/command endpoint. Using execute_command_replicat in the oggrestapi Python client:

from oggrestapi import OGGRestAPI

client = OGGRestAPI(url="http://localhost:7810", username="ogg", password="ogg")

resp = client.execute_command_replicat("REP1", data={"command": "INFO", "arguments": "DETAIL"})
output = "".join(r["reply"])
print(output)
Replicat   REP1      Last Started 2026-09-20 13:29   Status RUNNING
Checkpoint Lag       00:00:00 (updated 00:00:02 ago)
Process ID           102660
Log Read Checkpoint  File aa000000002
                     2026-09-20 13:30:17.000000  RBA 18926
Encryption Profile   LocalWallet

Current Log BSN value: 52643543

Last Committed Transaction CSN value: 52646310

  Extract Source                          Begin             End

  aa000000002                             2020-01-01 00:00  2026-09-20 13:30:17.00
  aa000000000                             * Initialized *   2020-01-01 00:00:00.00
  aa000000000                             * Initialized *   First Record

To be truly automated, Last Committed Transaction CSN value has to be parsed out:

import re

match = re.search(r"Last Committed Transaction CSN value: (\d+)", output)
applied_csn = int(match.group(1))
print(applied_csn)
52646310
Information in the report file

When starting a replicat during an initial load, the report file is filled with the following lines:

OGG-10155  Instantiation CSN filtering is enabled on table PDB1.APP_PDB1.ORDERS at CSN 52,642,649.
OGG-10185  Instantiation CSN filtering on table PDB1.APP_PDB1.ORDERS has started at CSN 52642649.
OGG-10186  Instantiation CSN filtering on table PDB1.APP_PDB1.ORDERS has ended, now passing transactions starting at CSN 52642649.
  • If the trail the replicat reads on that start contains records below a boundary, it filters them, and these lines appear.
  • If the trail begins at or after the boundary, nothing is filtered and no line appears at all.
Performance impact of leaving ENABLE_INSTANTIATION_FILTERING

When migrating a database online with GoldenGate, you want your replicat to catch up quickly. I tested whether keeping ENABLE_INSTANTIATION_FILTERING in the parameter file had any effect on the lag of a replicat. I found no significant statistical evidence of this.

Summary
  • ENABLE_INSTANTIATION_FILTERING is safe to remove when the replicat log_csn (last applied CSN) is above the instantiation_scn of every table it maps.
  • Get the applied CSN from oggadmin.checkpoint.log_csn (sqlplus), INFO REPLICAT REP1, DETAIL (adminclient), or execute_command_replicat("REP1", data={"command": "INFO", "arguments": "DETAIL"}) over REST, which returns the same information.
  • The OGG-10155/10185/10186 report lines appear only when the replicat filters records on that start.

L’article Removing instantiation filtering from a GoldenGate replicat est apparu en premier sur dbi Blog.

Database Space Usage

Tom Kyte - Sun, 2026-10-11 23:04
We are in the process of purging/deleting data from some large tables ex. Our F42199 table had 63 million rows from which we deleted 10 million rows. Since deleting the 10 million rows we have inserted 4 millions new rows Prior to purging the 10 million rows the size of the F42199 table was 158GB derived by querying the dba_extents view. Today the table has grown to 260 GB, much to our surprise as we thought the empty blocks from the deleted rows would be reused. So the question is why are the empty blocks not being reused or why is the table size increasing?
Categories: DBA Blogs

Oracle Spatial Studio

Tom Kyte - Sun, 2026-10-11 23:04
Can an end user create spatial data in Oracle Spatial Studio by digitizing as line or polygon on an apex created front- end map screen and if so, can the user digitized feature be stored as sdo geometry in the Oracle database? For example, a technician entering a road project text data would be able to digitize the road within the Oracle cloud infrastructure using oracle spatial studio like you can with qgis and postgresql.
Categories: DBA Blogs

Striim 5.4.2 on macOS: Using Oracle Instant Client 26ai Drivers

DBASolved - Sun, 2026-10-11 16:08

Running Striim 5.4.2 on macOS against Oracle 26ai? Swap the bundled 21 drivers for Instant Client jars and set NATIVE_LIBS.

The post Striim 5.4.2 on macOS: Using Oracle Instant Client 26ai Drivers appeared first on DBASolved.

Categories: DBA Blogs

Before the Ice Cream Melts: Catching Refrigeration Trouble Early with Oracle AI Data Platform

Pakistan's First Oracle Blog - Sat, 2026-10-10 00:14

A refrigerated truck rarely fails with a bang. It drifts. The trick is noticing the drift while the cargo is still safe.

A Tuesday Night on the Highway

Picture a fleet of refrigerated trucks carrying vaccines, dairy, and frozen food overnight. Each truck produces a steady stream of readings: cargo temperature, compressor current, door-open time, vibration, and fuel use. Those readings usually sit in separate places, such as telematics portals, maintenance systems, and spreadsheets.


When someone has to hunt across all of them, problems get found late. This post sketches how a fleet operator could use Oracle Cloud Infrastructure (OCI) and Oracle AI Data Platform to connect those signals and move from reacting to predicting. It is an adapted scenario based on a published Oracle reference approach for industrial IoT, not a customer case.

The Cast of Oracle Services Oracle AI Data Platform

The backbone. It brings ingestion, processing, storage, analytics, and AI into one connected foundation, so raw truck telemetry becomes curated data that other teams can reuse.

OCI Streaming

The intake pipe. Spark publishes sensor events to it through its Apache Kafka-compatible endpoint, which moves high-volume readings toward processing.

Spark on OCI

The cleanup crew. It validates and enriches incoming data and standardizes timestamps, units, and measurements, so a Fahrenheit reading from one truck and a Celsius reading from another do not get mixed up.

Oracle Analytics Cloud

The control room screen. Dispatchers and maintenance planners see trends, anomaly flags, and forecasts in shared dashboards.

Oracle Fusion Data Intelligence

The memory. It can combine maintenance history and work-order data with the operational picture, so a strange reading can be compared with what was last repaired on that unit.

Following One Reading from Truck to Technician
  1. Sense. Sensors on the trailer capture temperature, compressor behavior, and door activity.
  2. Stream. Events flow into OCI Streaming through the Kafka-compatible endpoint.
  3. Prepare. Spark checks, enriches, and standardizes the data.
  4. Store. Object Storage and data-lake layers keep both current and historical readings.
  5. Learn. Models flag unusual behavior and forecast where signals are heading.
  6. Show and alert. Dashboards and notifications reach the people who can act.

Good predictions depend on good data first. The machine learning only works if the pipeline underneath it is reliable and consistent.

Smarter Than a Fixed Alarm

A simple threshold alarm only fires after the temperature crosses a line. Anomaly detection looks at patterns across signals, such as a compressor drawing more current while the cargo temperature creeps upward. That pattern can deserve attention even though no single reading has crossed a limit yet.

Forecasting adds time. If a signal is expected to keep moving the wrong way, planners get a chance to schedule a check at the next depot instead of dealing with a spoiled load on the road.

What a Good Alert Looks Like

An alert can name the affected signal, the truck or trailer, and the time of the event. The people receiving it should treat it as a prompt to look closer, not as proof that something has broken. They confirm against the dashboard trend, decide whether to inspect, and record what they decided.

Two Screens That Do the Heavy Lifting Fleet health view in Oracle Analytics Cloud

Dashboards can combine sensor trends, anomaly indicators, forecasts, maintenance dates, and work-order readiness. One page answers the question: which trailers need eyes on them first?

Maintenance context in Fusion Data Intelligence

Teams can identify units with higher anomaly rates, compare predicted maintenance dates with scheduled ones, and review asset trends. That helps with prioritizing work and with efforts to limit unplanned downtime.

Ask Questions in Plain Language

The same curated data can feed AI-assisted reporting. A manager could ask which routes showed the most door-open anomalies this week and explore possible causes without waiting for a separate report. Oracle also notes that Oracle Analytics Cloud data models can be reached through supported MCP clients for natural-language and developer workflows. The MCP tools are described as a preview feature, so review the documentation before testing.

Five Things to Settle Before Launch
  • Data rules. Agree on expected ranges, units, timestamp conventions, and what happens when a sensor goes quiet.
  • Who owns each alert. Name the responsible team, severity levels, notification channel, and escalation path.
  • Model upkeep. Track false alarms and misses, watch for drift, and decide when to retrain or roll back.
  • Access control. Consider least-privilege access, OCI IAM policies, compartment boundaries, encryption, network controls, and audit logging.
  • A human in the loop. Decide how alerts get verified, how decisions are recorded, and how outcomes are reviewed.
Where to Go Next

Start by reading the documentation for OCI Streaming, Oracle AI Data Platform, Oracle Analytics Cloud, and Oracle Fusion Data Intelligence. Then test the pipeline, access controls, model monitoring, and response workflow against your own fleet and your own cargo rules.

The Takeaway

The value is not in collecting more data. It is in connecting what you already collect so the right person sees the right signal early enough to act. Done well, that points toward fewer unplanned breakdowns, steadier cargo quality, and calmer nights for dispatch.

Categories: DBA Blogs

Pages

Subscribe to Oracle FAQ aggregator