Oracle BINARY_FLOAT: 2 integers give same value? - oracle

I have a table full of 10-digit integers and thought to speed up queries/math in Oracle by storing them as BINARY_FLOAT. That's more CPU-friendly than NUMBER and won't take as much space (I think), which means more data in memory.
However, it appears that BINARY_FLOAT yields the same bytes (and hence value) for two different numbers...which obviously won't work.
Example:
SQL> select dump(to_binary_float(25185387)) from dual;
DUMP(TO_BINARY_FLOAT(2518538
----------------------------
Typ=100 Len=4: 203,192,38,54
SQL> select dump(to_binary_float(25185388)) from dual;
DUMP(TO_BINARY_FLOAT(2518538
----------------------------
Typ=100 Len=4: 203,192,38,54
SQL> CREATE TABLE blah ( somenum BINARY_FLOAT );
Table created.
SQL> insert into blah (somenum) values (25185387);
1 row created.
SQL> insert into blah (somenum) values (25185388);
1 row created.
SQL> select somenum from blah;
SOMENUM
----------
2.519E+007
2.519E+007
SQL> select to_number(somenum) from blah;
TO_NUMBER(SOMENUM)
------------------
25185388
25185388
SQL> select dump(somenum) from blah;
DUMP(SOMENUM)
------------------------------------------------------------------------------------------------------------------------
Typ=100 Len=4: 203,192,38,54
Typ=100 Len=4: 203,192,38,54
I expected that if I got into floating point, I might have some problem, but these are integers. I've tried various incantations - 25185387f, 25185387.0, 25185387*1.0, to_number(25185387), etc.
As I read the docs, BINARY_FLOAT should store to 1.79e308, so it can't be a rounding problem.
I'm using Oracle 11.2.0.3 on a 64-bit platform.
Ideas? Thanks.

Since the implementation of the oracle is BINARY_FLOAT standard ieee 754. BINARY_FLOAT is same as singe.
single have only 23 bits for significant bits.
25185387 = 11000000001001100011010 11 (length = 25)
25185388 = 11000000001001100011011 00 (length = 25)
hence the importance of these oracle rounds, discarding the least significant bits
25185387 ~ 11000000001001100011011 * 2^2
25185388 ~ 11000000001001100011011 * 2^2
so get the same value

Related

Using EXECUTE IMMEDIATE based on entries of table

I (using Oracle 12c, PL/SQL) need to update an existing table TABLE1 based on information stored in a table MAP. In a simplified version, MAP looks like this:
COLUMN_NAME
MODIFY
COLUMN1
N
COLUMN2
Y
COLUMN3
N
...
...
COLUMNn
Y
COLUMN1 to COLUMNn are column names in TABLE1 (but there are more columns, not just these). Now I need to update a column in TABLE1 if MODIFY in table MAP contains a 'Y' for that columns' name. There are other row conditions, so what I would need would be UPDATE statements of the form
UPDATE TABLE1
SET COLUMNi = value_i
WHERE OTHER_COLUMN = 'xyz_i';
where COLUMNi runs through all the columns of TABLE1 which are marked with MODIFY = 'Y' in MAP. value_i and xyz_i also depend on information stored in MAP (not displayed in the example).
The table MAP is not static but changes, so I do not know in advance which columns to update. What I did so far is to generate the UPDATE-statements I need in a query from MAP, i.e.
SELECT <Text of UPDATE-STATEMENT using row information from MAP> AS SQL_STMT
FROM MAP
WHERE MODIFY = 'Y';
Now I would like to execute these statements (possibly hundreds of rows). Of course I could just copy the contents of the query into code and execute, but is there a way to do this automatically, e.g. using EXECUTE IMMEDIATE? It could be something like
BEGIN
EXECUTE IMMEDIATE SQL_STMT USING 'xyz_i';
END;
only that SQL_STMT should run through all the rows of the previous query (and 'xyz_i' varies with the row as well). Any hints how to achieve this or how one should approach the task in general?
EDIT: As response to the comments, a bit more background how this problem emerges. I receive an empty n x m Matrix (empty except row and column names, think of them as first row and first column) quarterly and need to populate the empty fields from another process.
The structure of the initial matrix changes, i.e. there may be new/deleted columns/rows and existing columns/rows may change their position in the matrix. What I need to do is to take the old version of the matrix, where I already have filled the empty spaces, and translate this into the new version. Then, the populating process merely looks if entries have changed and if so, alters them.
The situation from the question arises after I have translated the old version into the new one, before doing the delta. The new matrix, populated with the old information, is TABLE1. The delta process, over which I have no control, gives me column names and information to be entered into the cells of the matrix (this is table MAP). So I need to find the column in the matrix labeled by the delta process and then to change values in rows (which ones is specified via other information provided by the delta process)
Dynamic SQL it is; here's an example, see if it helps.
This is a table whose contents should be modified:
SQL> select * from test order by id;
ID NAME SALARY
---------- ---------- ----------
1 Little 100
2 200
3 Foot 0
4 0
This is the map table:
SQL> select * from map;
COLUMN CB_MODIFY VALUE WHERE_CLAUSE
------ ---------- ----- -------------
NAME Y Scott where id <= 3
SALARY N 1000 where 1 = 1
Procedure loops through all columns that are set to be modified, composes the dynamic update statement and executes it:
SQL> declare
2 l_str varchar2(1000);
3 begin
4 for cur_r in (select m.column_name, m.value, m.where_clause
5 from map m
6 where m.cb_modify = 'Y'
7 )
8 loop
9 l_str := 'update test set ' ||
10 cur_r.column_name || ' = ' || chr(39) || cur_r.value || chr(39) || ' ' ||
11 cur_r.where_clause;
12 execute immediate l_str;
13 end loop;
14 end;
15 /
PL/SQL procedure successfully completed.
Result:
SQL> select * from test order by id;
ID NAME SALARY
---------- ---------- ----------
1 Scott 100
2 Scott 200
3 Scott 0
4 0
SQL>

Execute immediate use in select * from in oracle

I am trying to get maximum length of column data in oracle by executing a dynamic query as part of Select statement , except seems i don't think we can use execute immediate in an select clause. Could i get some help with syntax or understanding as to better way to do this.
SELECT
owner OWNER,
table_name,
column_name,
'select max(length('||column_name||')) from '||table_name||';' max_data_length
FROM
dba_tab_columns
WHERE
AND ( data_type = 'NUMBER'
OR data_type = 'INTEGER' )
the 4th column in above query spits out a sql string rather than computing the value and returning it.
Here is some food for thought. Note that I am only looking for numeric columns that don't already have precision specified in the catalog. (If you prefer, you can audit all numeric columns and compare the declared precision against the actual precision used by your data.)
I am also looking only in specific schemas. Instead, you may give a list of schemas to be ignored; I hope you are not seriously considering making any changes to SYS, for example, even if it does (and it does!) have numeric columns without specified precision.
The catalog doesn't store INTEGER in the data type; instead, it stores that as NUMBER(38) So I am not searching for data type INTEGER in DBA_TAB_COLUMNS. But this raises an interesting question - perhaps you should search for all columns where DATA_PRECISION is null (as in my code below), but also for DATA_PRECISION = 38.
In the code below I use DBMS_OUTPUT to display the findings directly to the screen. You will probably want to do something smarter with this; either create a table function, or create a table and insert the findings in it, or perhaps even issue DDL already (note that those also require dynamic SQL).
This still leaves you to deal with scale. Perhaps you can get around that with a specification like NUMBER(prec, *) - not sure if that will meet your needs. But the idea is similar; you will just need to write code carefully, like I did for precision (accounting for the decimal point and the minus sign, for example).
Long story short, here is what I ran on my system, and the output it produced.
declare
prec number;
begin
for rec in (
select owner, table_name, column_name
from all_tab_columns
where owner in ('SCOTT', 'HR')
and data_type = 'NUMBER'
and data_precision is null
)
loop
execute immediate
'select max(length(translate(to_char(' || rec.column_name ||
'), ''0-.'', ''0'')))
from ' || rec.owner || '.' || rec.table_name
into prec;
dbms_output.put_line('owner: ' || lpad(rec.owner, 12, ' ') ||
' table name: ' || lpad(rec.table_name, 12, ' ') ||
' column_name: ' || lpad(rec.column_name, 12, ' ') ||
' precision: ' || prec);
end loop;
end;
/
PL/SQL procedure successfully completed.
owner: HR table name: REGIONS column_name: REGION_ID precision: 1
owner: HR table name: COUNTRIES column_name: REGION_ID precision: 1
owner: SCOTT table name: SALGRADE column_name: GRADE precision: 1
owner: SCOTT table name: SALGRADE column_name: LOSAL precision: 4
owner: SCOTT table name: SALGRADE column_name: HISAL precision: 4
PL/SQL procedure successfully completed.
EDIT
Here are several additional points (mostly, corrections) based on extended conversations with Sayan Malakshinov in comments to my answer and to his.
Most importantly, even if we can figure out max precision of numeric columns, that doesn't seem directly related to the ultimate goal of this whole thing, which is to determine the correct Postgre data types for the existing Oracle columns. For example in Postgre, unlike Oracle, it is important to distinguish between integer and non-integer. Unless scale is explicitly 0 in Oracle, we don't know that the column is "integers only"; we could find that out, through a similar dynamic SQL approach, but we would be checking for non-integer values, not precision.
Various corrections: My query is careless with regard to quoted identifiers (schema name, table name, column name). See the proper use of double-quotes in the dynamic query in Sayan's answer; my dynamic query should be modified to use double-quotes in the same way his does.
In my approach I pass numbers through TO_CHAR and then remove minus sign and decimal period. Of course, one's system may use comma, or other symbols, for decimal separator; the safer approach is to remove everything that is not a digit. That can be done with
translate(col_name, '0123456789' || col_name, '0123456789')
The query also doesn't handle very large or very small numbers, which can be stored in the Oracle database, but can only be represented in scientific notation when passed through TO_CHAR().
In any case, since "max precision" doesn't seem directly related to the ultimate goal of mapping to correct data types in Postgre, I am not changing the code - leaving it in the original form.
Thanks to Sayan for pointing out all these issues.
One more thing - *_TAB_COLUMNS contains information about view columns too; very likely those should be ignored for the task at hand. Very easy to do, as long as we realize it needs to be done.
Reading carefully that AWS article and since both previous answers (including mine) use rough estimate (length+to_char without format model and vsize operate decimal length, not bytes), I decided to write another full answer.
Look at this simple example:
with
function f_bin(x number) return varchar2 as
bi binary_integer;
e_overflow exception;
pragma exception_init(e_overflow, -1426);
begin
bi:=x;
return case when bi=x then 'ok' else 'error' end;
exception when e_overflow then return 'error';
end;
function f_check(x number, f varchar2) return varchar2 as
begin
return case when to_number(to_char(abs(x),f),f) = abs(x) then 'ok' else 'error' end;
exception when VALUE_ERROR then return 'error';
end;
a(a1) as (
select * from table(sys.odcinumberlist(
1,
0.1,
-0.1,
-7,
power(2,15)-1,
power(2,16)-1,
power(2,31)-1,
power(2,32)-1
))
)
select
a1,
f_check(a1,'fm0XXX') byte2,
f_check(a1,'fm0XXXXXXX') byte4,
f_bin(a1) ff_signed_binary_int,
to_char(abs(a1),'fm0XXXXXXXXXXXXXXX') f_byte8,
f_check(a1,'fm0XXXXXXXXXXXXXXX') byte8,
vsize(a1) vs,
dump(a1) dmp
from a;
Result:
A1 BYTE2 BYTE4 FF_SIGNED_ F_BYTE8 BYTE8 VS DMP
---------- ---------- ---------- ---------- ---------------- ---------- ---------- ----------------------------------------
1 ok ok ok 0000000000000001 ok 2 Typ=2 Len=2: 193,2
.1 error error error 0000000000000000 error 2 Typ=2 Len=2: 192,11
-.1 error error error 0000000000000000 error 3 Typ=2 Len=3: 63,91,102
-7 ok ok ok 0000000000000007 ok 3 Typ=2 Len=3: 62,94,102
32767 ok ok ok 0000000000007FFF ok 4 Typ=2 Len=4: 195,4,28,68
65535 ok ok ok 000000000000FFFF ok 4 Typ=2 Len=4: 195,7,56,36
2147483647 error ok ok 000000007FFFFFFF ok 6 Typ=2 Len=6: 197,22,48,49,37,48
4294967295 error ok error 00000000FFFFFFFF ok 6 Typ=2 Len=6: 197,43,95,97,73,96
Here I used PL/SQL functions for readability and to make it more clear.
Function f_bin casts an input number parameter to PL/SQL binary_integer (signed int4) and compares the result with input parameter, ie it checks if it loses accuracy. Defined exception shows that it can raise an exception 1426 "numeric overflow".
Function f_check does double conversion to_number(to_char(...)) of the input value and checks if it's still equal to the input value. Here I use hexadecimal format mask (XX = 1 byte), so it checks if an input number can fit an in this format mask. Hexadecimal format model works with non-negative numbers, so we need to use abs() here.
F_BYTE8 shows formatted value that uses a function from the column BYTE8, so you can easily see the loss of accuracy here.
All the above were just for readability, but we can make the same using just pure SQL:
with
a(a1) as (
select * from table(sys.odcinumberlist(
1,
0.1,
-0.1,
-7,
power(2,15)-1,
power(2,16)-1,
power(2,31)-1,
power(2,32)-1
))
)
select
a1,
case when abs(a1) = to_number(to_char(abs(a1),'fmXXXXXXXXXXXXXXX') default null on conversion error,'fmXXXXXXXXXXXXXXX')
then ceil(length(to_char(abs(a1),'fmXXXXXXXXXXXXXXX'))/2)
else -1
end xx,
vsize(a1) vs,
dump(a1) dmp
from a;
Result:
A1 XX VS DMP
---------- ---------- ---------- ----------------------------------------
1 1 2 Typ=2 Len=2: 193,2
.1 -1 2 Typ=2 Len=2: 192,11
-.1 -1 3 Typ=2 Len=3: 63,91,102
-7 1 3 Typ=2 Len=3: 62,94,102
32767 2 4 Typ=2 Len=4: 195,4,28,68
65535 2 4 Typ=2 Len=4: 195,7,56,36
2147483647 4 6 Typ=2 Len=6: 197,22,48,49,37,48
4294967295 4 6 Typ=2 Len=6: 197,43,95,97,73,96
As you can see, here I return -1 in case of conversion errors to byte8 and number of non-zero bytes otherwize.
Obviusly it can be simplified even more: you can just check range limits and that x=trunc(x) or mod(x,1)=0.
Looks like that is what you need:
VSIZE returns the number of bytes in the internal representation of expr. If expr is null, then this function returns null.
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/VSIZE.html
In Oracle INTEGER is just a number(*,0): http://orasql.org/2012/11/10/differences-between-integerint-in-sql-and-plsql/
select
owner,table_name,column_name,
data_type,data_length,data_precision,data_scale,avg_col_len
,x.vs
from (select/*+ no_merge */ c.*
from dba_tab_columns c
where data_type='NUMBER'
and owner not in (select username from dba_users where ORACLE_MAINTAINED='Y')
) c
,xmltable(
'/ROWSET/ROW/VSIZE'
passing dbms_xmlgen.getxmltype('select nvl(max(vsize("'||c.column_name||'")),0) as VSIZE from "'||c.owner||'"."'||c.table_name||'"')
columns vs int path '.'
) x
;
Update: if you read oracle internal number format (exponent+bcd-mantissa and look at a result of dump(x) function, you can see that Oracle stores numbers as a decimal value(4 bits per 1 decimal digit, 2 digits in 1 byte), so for such small ranges you can just take their maximum BCD mantissa+1 exponent as a rough estimation.

oracle forms 12. how to display leading zero of decimal numbers

I wish to display decimal numbers (from a query) into text items.
if I set
:TXT_ITEM := '0,000123456789'
it works. But, if :TXT_ITEM is bound to a numeric table field, value is displayed as ,000123456789.
I'm trying to force format number on several triggers (post-change, when-new-record-instance, post-text...), unsuccessfully. On other hand, setting format_mask would force my DB value to a given number of decimal digits.
How can I get leading zero to be displayed?
See if any of these two options help.
Sample data:
SQL> create table test as
2 (select 12.34 col from dual union all
3 select 0.1234003 from dual union all
4 select -13.43432203 from dual union all
5 select 0.00012345221 from dual union all
6 select -0.002412428238234821 from dual
7 );
Table created.
SQL> desc test;
Name Null? Type
----------------------------------------- -------- ----------------------------
COL NUMBER
SQL> select col,
2 regexp_replace(col, '^(-?)([.,])', '\10\2') result1,
3 rtrim(to_char(col, 'fm90D999999999999999999999'), '.') result2
4 from test;
COL RESULT1 RESULT2
---------- ------------------------- -------------------------
12,34 12,34 12,34
,1234003 0,1234003 0,1234003
-13,434322 -13,43432203 -13,43432203
,000123452 0,00012345221 0,00012345221
-,00241243 -0,002412428238234821 -0,002412428238234821
SQL>
How would use it/them in Forms? Exactly like that - you'd e.g.
select regexp_replace(col, '^(-?)([.,])', '\10\2')
into :block.text_item
from your_table
where some_condition;
Seems the concerned numeric data in the table is of type
NUMBER(13,12)
in this case it's enough to set TXT_ITEMs Format Mask attribute within the Data part of Property Palette as
0D000000000000
with precision of 13 and scale of 12 values.
Considering the scale part is fixed, you can add more zeroes before D character depending on your column's precision value such as two zeroes before D are kept for NUMBER(14,12) or three zeroes for NUMBER(15,12).

Why oracle doesn't show the integer part of a decimal

when I execute the next SQL:
select 1/3 from dual;
the result is ,333333333
but the result that I expected was 0,333333333
Why doesn't oracle show the zero ? is there any parameter that can affect it?
Thanks
Edit: I checked this behaviour from an aplication that uses the oo4o (oracle object for ole), and confirmed with the sqlDeveloper (when I execute the sql with F5, not with ctrl+intro). The real problem is with the oo4o Dynaset object: when I try to sum the value of two fields, what I get is a concatenation, not a sum: ,3 + ,2 = ,3,2.
What I want to know is if there is some parameter or configuration that makes the oracle engine return the number without the zero, so I can turn on|off in order to return de zero as integer part.
SQL*Plus will show that by default (using your territory's decimal separator):
SQL> select 1/3 from dual;
1/3
----------
.333333333
You could use set numformat to change the behaviour:
SQL> set numformat "0D9999"
SQL> select 1/3 from dual;
1/3
-------
0.3333
... where the D represents the decimal separator. Or you could use column formatting, with a column alias:
SQL> set numformat ""
SQL> column answer format 0.000
SQL> select 1/3 as answer from dual;
ANSWER
------
0.333
Other clients have different ways of controlling the default output; SQL Developer behaves much the same, but PL/SQL Developer, Toad etc. might not.
Or you can format the number as part of the query, which isn't client-dpendent:
SQL> select to_char(1/3, '9990D99999') from dual;
TO_CHAR(1/3
-----------
0.33333
You need to provide enough digits for the integer part of whatever you're calculating though. Anything less than zero is simple, but if there are too many digits before the decimal separator then it won't display at all:
SQL> select to_char(100000/3, '9990D99999') from dual;
TO_CHAR(100
-----------
###########

Oracle trouble in getting data from a partitioned table

On a new job I have to figure out how some database reporting scripts are working.
There is one table that is giving me some trouble. I see in existing scripts that it is a partitioned table.
My problem is that whatever query I run on this table returns me "no rows selected".
Here are some details about my investigation in this table:
Table size estimate
SQL> select sum(bytes)/1024/1024 Megabytes from dba_segments where segment_name = 'PPREC';
MEGABYTES
----------
45.625
Partitions
There are a total of 730 partitions on date range.
SQL> select min(PARTITION_NAME),max(PARTITION_NAME) from dba_segments where segment_name = 'PPREC';
MIN(PARTITION_NAME) MAX(PARTITION_NAME)
------------------------------ ------------------------------
PART20110201 PART20130130
There are several tablespaces and partitions are allocated in them
SQL> select tablespace_name, count(partition_name) from dba_segments where segment_name = 'PPREC' group by tablespace_name;
TABLESPACE_NAME COUNT(PARTITION_NAME)
------------------------------ ---------------------
REC_DATA_01 281
REC_DATA_02 48
REC_DATA_03 70
REC_DATA_04 26
REC_DATA_05 44
REC_DATA_06 51
REC_DATA_07 13
REC_DATA_08 48
REC_DATA_09 32
REC_DATA_10 52
REC_DATA_11 35
REC_DATA_12 30
Additional query:
SQL> select * from dba_segments where segment_name='PPREC' and partition_name='PART20120912';
OWNER SEGMENT_NAME PARTITION_NAME SEGMENT_TYPE TABLESPACE_NAME HEADER_FILE HEADER_BLOCK BYTES BLOCKS EXTENTS
----- ------------ -------------- --------------- --------------- ----------- ------------ ----- ------ -------
HIST PPREC PART20120912 TABLE PARTITION REC_DATA_01 13 475315 65536 8 1
INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS PCT_INCREASE FREELISTS FREELIST_GROUPS RELATIVE_FNO BUFFER_POOL
-------------- ----------- ----------- ----------- ------------ --------- --------------- ------------ -----------
65536 1 2147483645 13 DEFAULT
Tabespace usage
Here is a space summary (composite of dba_tablespaces, dba_data_files, dba_segments, dba_free_space)
TABLESPACE_NAME TOTAL_MEGABYTES USED_MEGABYTES FREE_MEGABYTES
------------------------------ --------------- -------------- --------------
REC_01_INDX 30,700 250 30,449
REC_02_INDX 7,745 7 7,737
REC_03_INDX 22,692 15 22,677
REC_04_INDX 15,768 10 15,758
REC_05_INDX 25,884 16 25,868
REC_06_INDX 27,992 16 27,975
REC_07_INDX 17,600 10 17,590
REC_08_INDX 18,864 11 18,853
REC_09_INDX 19,700 12 19,687
REC_10_INDX 28,716 16 28,699
REC_DATA_01 102,718 561 102,156
REC_DATA_02 24,544 3,140 21,403
REC_DATA_03 72,710 4 72,704
REC_DATA_04 29,191 2 29,188
REC_DATA_05 42,696 3 42,692
REC_DATA_06 52,780 323 52,456
REC_DATA_07 16,536 1 16,534
REC_DATA_08 49,247 3 49,243
REC_DATA_09 30,848 2 30,845
REC_DATA_10 49,620 3 49,616
REC_DATA_11 40,616 2 40,613
REC_DATA_12 184,922 123,435 61,486
The tablespace usage seems to confirm that this table is not empty, in fact its last tablespace (REC_DATA_12) seems pretty busy.
Existing scripts
What I find puzzling is that there are some PL/SQL stored procedures that seem to work on that table and get data out of it.
An example of such a stored procedure is as follows:
procedure FIRST_REC as
vpartition varchar2(12);
begin
select 'PART'||To_char(sysdate,'YYYYMMDD') INTO vpartition FROM DUAL;
execute immediate
'MERGE INTO FIRST_REC_temp a
USING (SELECT bno, min(trdate) mintr,max(trdate) maxtr
FROM PPREC PARTITION ('||vpartition||') WHERE route_id IS NOT NULL AND trunc(trdate) <= trunc(sysdate-1)
GROUP BY bno) b
ON (a.bno=b.bno)
when matched then
update set a.last_tr = b.maxtr
when not matched then
insert (a.bno,a.last_tr,a.first_tr)
values (b.bno,b.maxtr,b.mintr)';
commit;
However if I try using the same syntax manually on the table, here is what I get:
SQL> select count(*) from PPREC PARTITION (PART20120912);
COUNT(*)
----------
0
I have tried a few random partitions and I always get the same 0 count.
Summary
- I see a table that seems to contain data (space used, tablespaces, data files)
- The table is partitioned (one partition per day over a period of 730 days ending end of January 2013)
- Scripts are extracting data from that table somehow
Question
- My queries using PARTITION are all returning me "no rows selected". What am I doing wrong? How could I find out how to extract data from this table?
I suppose it's possible that some other process might be deleting the data, but without visiting your site there's no way for anyone here to tell if that might be so.
I don't see in your post that you mentioned the name of the partitioning DATE column, but based on the SQL you posted I'll assume it's TRDATE - if this is not correct, change TRDATE in the statement below to be the partitioning column.
That said, give this a try:
SELECT COUNT(*)
FROM PPREC
WHERE TRDATE >= TO_DATE('01-SEP-2012 00:00:00', 'DD-MON-YYYY HH24:MI:SS')
This assumes you should have data in this table from September. If you find data, great. If you don't - well, Back In The Day (when men were men, women were women, and computers were water-cooled :-) we had a little saying about memory on IBM mainframes:
1. If you can see it, and it's there, it's Real.
2. If you can't see it, but it's there, it's Protected.
3. If you can see it, but it's not there, it's Virtual.
4. If you can't see it, and it's not there, it's GONE!
:-)
Use of the PARTITION clause should be reserved for situations where you are experiencing a performance problem (note: guessing about what is or is not going to be a performance problem is not allowed. Until you've got a performance problem you don't have a performance problem. Over the years I've found that software spends a lot of execution time in the darndest places :-), and the usual fixes (adding indexes, deleting unnecessary data, human sacrifice, etc) haven't worked. Basically, write your queries normally and trust the database to get it right. (In the general case - always write the simplest code - and do the simplest thing - that could possibly work. 99+ percent of the time it will be fine. That allows you to spend your optimization time on the less-than-one-percent cases where simple isn't good enough - and most of the software you write or design will be simple and easy to understand).
Share and enjoy.

Resources