Proxysql query rule starting with comment didn't work - proxysql

On proxyql 2.2.0
I've the following rule which isn't working (stats_mysql_query_rules counter always on 0).
INSERT INTO mysql_query_rules (active, match_digest, destination_hostgroup, apply, multiplex) VALUES (1, '/\* Master \*/', 1, 1, 1);
This rule is in number position on my mysql_query_rules table.
The idea is to catch query like this one and push them to my Master node (AWS RDS Aurora writer endpoint).
/* Master */
select * from my_table;
Regex seems OK but the rule didn't (and query is counted on other rules).

The documentation isn't explicit about it but it seems that query rules match_digest evaluation is stripping comments (e.g. /* Comments */) within SQL queries. So the pattern used above need to be insert inside the match_pattern field

Related

Oracle not using an index in a simple query, despite the hint

I have a table with column status. It is a string nullable column. I also have an index on this field only. Why is the following query not using the index?
select /*+ index(m IDX_STATUS) */ * from messages m where m.status = :1
Try running the query without named (bind) parameters. Sometimes that makes a big difference.
select * from messages m where m.status = 'P'
It may turn out that you don't even need a hint to trigger index usage.
A possible explanation is that the column contains many equal values, for example 90% of rows has status = 'D' (low-cardinality column). Now we can understand Oracle, why it did not use the index :) It simply doesn't make sense on value 'D', but is reasonable for other values. I would prefer Oracle to consider my hint (I know better), but that seems undoable.
In general there is an extremely useful guide Oracle SQL Tuning Guide: The index is being ignored. Still it does not mention the situation, where omitting bind parameter makes the problem go away. That's why I insisted on asking the question on SO.

Offset Management - Confluent JDBC Connector in query mode

As per the confluent documentation, when we use the query mode, we have to do the offset management. As per my understanding, we need to keep track of the last updated timestamp and pass it in the where clause when we restart the program each time. Could anyone confirm if the understanding is correct? Appreciate your help in advance!
You can do both - you can still set the timestamp and incrementing mode in addition to the query. it will simply add a where statement based on timestamp.column.name and/or incrementing.column.name field. You can even use a subquery if your query needs a where statement
As an example you could set your query to: select * from (select apples from tree where color = green) as subquery
with the timestamp.column.name set to ripedate the sql kafka will execute is:
select * from (select apples from tree where color = green) as subquery where ripedate > offsetdate

How can I use having without group by?

I am reading about having clause in oracle.
It is written in the docs that
If there is no GROUP BY clause, the HAVING clause is applied to the
entire result as a single group.
But whenever I tried to use having clause without group by, I am getting syntax error.
How can I use having without group by?
Can somebody explain me with this schema?
SQL fiddle
A simple experiment will prove that this is possible:
select * from dual having 1=1
This query will run successfully in Oracle 11g. I suspect the problem you're seeing is that you're trying to use an aggregate function in the having clause and that is not allowed with a group by clause.
While it's clearly possible to use having without group by, I don't really see any point. Any condition you would put in the having clause in this scenario would be more appropriate in the where clause.
HAVING without GROUP BY is valid. But also consider below points.
If there is no GROUP BY clause, the HAVING clause is applied to the entire result as a single group.
booleanExpression in HAVING can contain only grouping columns, columns that are part of aggregate expressions, and columns that are part of a subquery.
So when you are using HAVING without GROUP BY the following syntaxes are not valid.
1) SELECT col_x .... /* Since col_x is not a part of GROUP BY
or
2) HAVING col_x (in a boolean expression) /* Since col_x is not a part of GROUP BY
What instead of col_x in you can have is some Aggregate Function on col_x, or a constant, at both HAVING and SELECT clause.
Do not assume the whole table as one group means GROUP BY col_1, ....col_n

Transformation to choose datatable based on value in separate table

I have three tables (Oracle source), lets call them tables 1, 2, and 3.
I would like to check a boolean field in table 1, and if it is T I want only data from table 2, and if it is F, I want only table 3.
Which transformation would be the most efficient for doing so, and how would I go about implementing it?
I'm experimenting with the Filter, Java, and Expression transformations, but if the expressions are checking on a row-by-row basis, then it seems like overkill for the expression to run on every row instead of just checking once and using the appropriate table.
Both tables 2 and 3 have a field with the same name, and I want that field for just one of the tables, based on the condition.
Create a mapping similar to the following diagram:
src_TABLE2 --> sq_TABLE2 --|
|--> union --> (further processing)
src_TABLE3 --> sq_TABLE3 --|
and use the following Source Filter conditions* in the source qualifiers:
-- for sq_TABLE2
'T' = ( SELECT FLAG FROM TABLE1 )
-- for sq_TABLE3
'F' = ( SELECT FLAG FROM TABLE1 )
There are two source tables in the mapping and the union transformation merges data from these two pipelines. However, because of the filtering conditions at any given time data will be retrieved only from one of the source tables.
* Source Filter is an attribute on the Properties tab of a source qualifier. The condition you set here is appended to the WHERE clause of the SELECT statement that is sent to the database.

Oracle - Understanding the no_index hint

I'm trying to understand how no_index actually speeds up a query and haven't been able to find documentation online to explain it.
For example I have this query that ran extremely slow
select *
from <tablename>
where field1_ like '%someGenericString%' and
field1_ <> 'someSpecificString' and
Action_='_someAction_' and
Timestamp_ >= trunc(sysdate - 2)
And one of our DBAs was able to speed it up significantly by doing this
select /*+ NO_INDEX(TAB_000000000019) */ *
from <tablename>
where field1_ like '%someGenericString%' and
field1_ <> 'someSpecificString' and
Action_='_someAction_' and
Timestamp_ >= trunc(sysdate - 2)
And I can't figure out why? I would like to figure out why this works so I can see if I can apply it to another query (this one a join) to speed it up because it's taking even longer to run.
Thanks!
** Update **
Here's what I know about the table in the example.
It's a 'partitioned table'
TAB_000000000019 is the table not a column in it
field1 is indexed
Oracle's optimizer makes judgements on how best to run a query, and to do this it uses a large number of statistics gathered about the tables and indexes. Based on these stats, it decides whether or not to use an index, or to just do a table scan, for example.
Critically, these stats are not automatically up-to-date, because they can be very expensive to gather. In cases where the stats are not up to date, the optimizer can make the "wrong" decision, and perhaps use an index when it would actually be faster to do a table scan.
If this is known by the DBA/developer, they can give hints (which is what NO_INDEX is) to the optimizer, telling it not to use a given index because it's known to slow things down, often due to out-of-date stats.
In your example, TAB_000000000019 will refer to an index or a table (I'm guessing an index, since it looks like an auto-generated name).
It's a bit of a black art, to be honest, but that's the gist of it, as I understand things.
Disclaimer: I'm not a DBA, but I've dabbled in that area.
Per your update: If field1 is the only indexed field, then the original query was likely doing a fast full scan on that index (i.e. reading through every entry in the index and checking against the filter conditions on field1), then using those results to find the rows in the table and filter on the other conditions. The conditions on field1 are such that an index unique scan or range scan (i.e. looking up specific values or ranges of values in the index) would not be possible.
Likely the optimizer chose this path because there are two filter predicates on field1. The optimizer would calculate estimated selectivity for each of these and then multiply them to determine their combined selectivity. But in many cases this will significantly underestimate the number of rows that will match the condition.
The NO_INDEX hint eliminates this option from the optimizer's consideration, so it essentially goes with the plan it thinks is next best -- possibly in this case using partition elimination based on one of the other filter conditions in the query.
Using an index degrades query performance if it results in more disk IO compared to querying the table with an index.
This can be demonstrated with a simple table:
create table tq84_ix_test (
a number(15) primary key,
b varchar2(20),
c number(1)
);
The following block fills 1 Million records into this table. Every 250th record is filled with a rare value in column b while all the others are filled with frequent value:
declare
rows_inserted number := 0;
begin
while rows_inserted < 1000000 loop
if mod(rows_inserted, 250) = 0 then
insert into tq84_ix_test values (
-1 * rows_inserted,
'rare value',
1);
rows_inserted := rows_inserted + 1;
else
begin
insert into tq84_ix_test values (
trunc(dbms_random.value(1, 1e15)),
'frequent value',
trunc(dbms_random.value(0,2))
);
rows_inserted := rows_inserted + 1;
exception when dup_val_on_index then
null;
end;
end if;
end loop;
end;
/
An index is put on the column
create index tq84_index on tq84_ix_test (b);
The same query, but once with index and once without index, differ in performance. Check it out for yourself:
set timing on
select /*+ no_index(tq84_ix_test) */
sum(c)
from
tq84_ix_test
where
b = 'frequent value';
select /*+ index(tq84_ix_test tq84_index) */
sum(c)
from
tq84_ix_test
where
b = 'frequent value';
Why is it? In the case without the index, all database blocks are read, in sequential order. Usually, this is costly and therefore considered bad. In normal situation, with an index, such a "full table scan" can be reduced to reading say 2 to 5 index database blocks plus reading the one database block that contains the record that the index points to. With the example here, it is different altogether: the entire index is read and for (almost) each entry in the index, a database block is read, too. So, not only is the entire table read, but also the index. Note, that this behaviour would differ if c were also in the index because in that case Oracle could choose to get the value of c from the index instead of going the detour to the table.
So, to generalize the issue: if the index does not pick few records then it might be beneficial to not use it.
Something to note about indexes is that they are precomputed values based on the row order and the data in the field. In this specific case you say that field1 is indexed and you are using it in the query as follows:
where field1_ like '%someGenericString%' and
field1_ <> 'someSpecificString'
In the query snippet above the filter is on both a variable piece of data since the percent (%) character cradles the string and then on another specific string. This means that the default Oracle optimization that doesn't use an optimizer hint will try to find the string inside the indexed field first and also find if the data it is a sub-string of the data in the field, then it will check that the data doesn't match another specific string. After the index is checked the other columns are then checked. This is a very slow process if repeated.
The NO_INDEX hint proposed by the DBA removes the optimizer's preference to use an index and will likely allow the optimizer to choose the faster comparisons first and not necessarily force index comparison first and then compare other columns.
The following is slow because it compares the string and its sub-strings:
field1_ like '%someGenericString%'
While the following is faster because it is specific:
field1_ like 'someSpecificString'
So the reason to use the NO_INDEX hint is if you have comparisons on the index that slow things down. If the index field is compared against more specific data then the index comparison is usually faster.
I say usually because when the indexed field contains more redundant data like in the example #Atish mentions above, it will have to go through a long list of comparison negatives before a positive comparison is returned. Hints produce varying results because both the database design and the data in the tables affect how fast a query performs. So in order to apply hints you need to know if the individual comparisons you hint to the optimizer will be faster on your data set. There are no shortcuts in this process. Applying hints should happen after proper SQL queries have been written because hints should be based on the real data.
Check out this hints reference: http://docs.oracle.com/cd/B19306_01/server.102/b14211/hintsref.htm
To add to what Rene' and Dave have said, this is what I have actually observed in a production situation:
If the condition(s) on the indexed field returns too many matches, Oracle is better off doing a Full Table Scan.
We had a report program querying a very large indexed table - the index was on a region code and the query specified the exact region code, so Oracle CBO uses the index.
Unfortunately, one specific region code accounted for 90% of the tables entries.
As long as the report was run for one of the other (minor) region codes, it completed in less than 30 minutes, but for the major region code it took many hours.
Adding a hint to the SQL to force a full table scan solved the problem.
Hope this helps.
I had read somewhere that using a % in front of query like '%someGenericString%' will lead to Oracle ignoring the INDEX on that field. Maybe that explains why the query is running slow.

Resources