How can I accelerate this MySQL query? - performance

geneHomology
============
id genome_name gene_id homolog_genome_name homolog_gene_id consider_homolog
1 HomoSap 1007 MusMus 824 1
2 HomoSap 1007 MusMus 825 1
3 HomoSap 1007 MusMus 826 1
4 HomoSap 2890 EColi 2140 1
...
gene
====
genome_name gene_id gene_category
MusMus 823 Upregulated
MusMus 824 Downregulated
MusMus 825 Normal
MusMus 826 Normal
MusMus 827 Upregulated
EColi 2140 Normal
...
consider_homolog is an enum (0,1). genome_name and gene_id are primary keys in gene. geneHomology is very large - some 200M rows.
My goal is to count for each gene in genes how many homologs it has from each gene_category.
For example, following the data above, HomoSap 1007 has 3 Normal homologs and 1 Downregulated.
So my query is:
SELECT a.id,a.genome_name,a.gene_id,a.homolog_genome_name,a.homolog_gene_id,COUNT(b.gene_category)
FROM geneHomology a,gene b
WHERE a.consider_homolog='1' AND a.homolog_genome_name=b.genome_name AND a.homolog_gene_id=b.gene_id
GROUP BY a.genome_name,a.gene_id,b.gene_category;
It never returns (and I've been patiently waiting for more than an hour).
I already indexed gene_category in gene.
I'm really new to MySQL but I have root access to the DB so I could follow your suggestions (carefully...). I would be happy to provide any further information.
UPDATE
This is the EXPLAIN output for the query:
+----+-------------+-------+------+-----------------------+----------------------+---------+----------------------------------------------------------+---------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-----------------------+----------------------+---------+----------------------------------------------------------+---------+---------------------------------+
| 1 | SIMPLE | b | ALL | PRIMARY,gene_genome | NULL | NULL | NULL | 1560695 | Using temporary; Using filesort |
| 1 | SIMPLE | a | ref | geneHomologyHit_gene | geneHomologyHit_gene | 54 | my_db_v71.b.gene_id,my_db_v71.b.genome_name | 13 | Using where |
+----+-------------+-------+------+-----------------------+----------------------+---------+----------------------------------------------------------+---------+---------------------------------+
UPDATE 2
mysql> SHOW INDEX FROM gene;
+-------+------------+--------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+--------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
| gene | 0 | PRIMARY | 1 | gene_id | A | NULL | NULL | NULL | | BTREE | |
| gene | 0 | PRIMARY | 2 | genome_name | A | 1560695 | NULL | NULL | | BTREE | |
| gene | 1 | gene_organism | 1 | taxon_id | A | 392 | NULL | NULL | | BTREE | |
| gene | 1 | gene_genome | 1 | genome_name | A | 853 | NULL | NULL | | BTREE | |
| gene | 1 | gene_gene_category | 1 | gene_category | A | 5 | NULL | NULL | | BTREE | |
+-------+------------+--------------------------+--------------+---------------------+-----------+-------------+----------+--------+------+------------+---------+
5 rows in set (0.01 sec)
UPDATE 3
mysql> SHOW INDEX FROM geneHomology;
+--------------+------------+------------------------+--------------+--------------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------------+------------+------------------------+--------------+--------------------------+-----------+-------------+----------+--------+------+------------+---------+
| geneHomology | 0 | PRIMARY | 1 | id | A | 680326661 | NULL | NULL | | BTREE | |
| geneHomology | 1 | geneHomologyQuery_gene | 1 | gene_id | A | 1498516 | NULL | NULL | | BTREE | |
| geneHomology | 1 | geneHomologyQuery_gene | 2 | genome_name | A | 1505147 | NULL | NULL | | BTREE | |
| geneHomology | 1 | geneHomologyHit_gene | 1 | homolog_gene_id | A | 52332820 | NULL | NULL | | BTREE | |
| geneHomology | 1 | geneHomologyHit_gene | 2 | homolog_genome_name | A | 52332820 | NULL | NULL | | BTREE | |
+--------------+------------+------------------------+--------------+--------------------------+-----------+-------------+----------+--------+------+------------+---------+
5 rows in set (0.00 sec)
UPDATE 4
Is there a way to get only partial results to even see I'm getting what I want? I tried LIMIT 1000 and even LIMIT 10 but it doesn't seem to change anything.
UPDATE 5
mysql> SHOW CREATE TABLE geneHomology;
+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| geneHomology | CREATE TABLE `geneHomology` (
`id` bigint(20) NOT NULL auto_increment,
`genome_name` varchar(20) NOT NULL,
`gene_id` varchar(30) NOT NULL,
`homolog_genome_name` varchar(20) NOT NULL,
`homolog_gene_id` varchar(30) NOT NULL,
`homolog_length` bigint(20) unsigned NOT NULL,
`significance` double unsigned NOT NULL,
`bit_score` double unsigned NOT NULL,
`percent_identity` double unsigned NOT NULL,
`start_match` int(10) unsigned NOT NULL,
`end_match` int(10) unsigned NOT NULL,
`start_match_percent` double unsigned NOT NULL,
`end_match_percent` double unsigned NOT NULL,
`strand` enum('+','-') default NULL,
`homolog_start_match` int(10) unsigned NOT NULL,
`homolog_end_match` int(10) unsigned NOT NULL,
`homolog_start_match_percent` double unsigned NOT NULL,
`homolog_end_match_percent` double unsigned NOT NULL,
`homolog_strand` enum('+','-') default NULL,
`consider_gene_homology` enum('0','1') NOT NULL,
`reason_not_considered` varchar(50) default NULL,
`num_hsps` int(10) unsigned NOT NULL,
`homology_type` varchar(2) NOT NULL,
PRIMARY KEY (`id`),
KEY `geneHomologygene` (`gene_id`,`genome_name`),
KEY `geneHomologyhomolog_gene` (`homolog_gene_id`,`homolog_genome_name`)
) ENGINE=MyISAM AUTO_INCREMENT=680326662 DEFAULT CHARSET=latin1 |
+--------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE gene;
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| gene | CREATE TABLE `gene` (
`taxon_id` int(10) unsigned NOT NULL,
`genome_name` varchar(20) NOT NULL,
`gene_id` varchar(30) NOT NULL,
`symbol` varchar(30) default NULL,
`type` varchar(30) default NULL,
`product` varchar(300) default NULL,
`strand` enum('+','-') NOT NULL,
`start` bigint(20) unsigned NOT NULL,
`end` bigint(20) unsigned NOT NULL,
`gene_category` enum('Upregulated','Downregulated','Normal','n/a') NOT NULL,
`consider_gene` enum('0','1') NOT NULL,
`reason_not_considered` varchar(50) default NULL,
`sequence` longblob NOT NULL,
`additional_info` varchar(300) default NULL,
PRIMARY KEY (`gene_id`,`genome_name`),
KEY `gene_organism` (`taxon_id`),
KEY `gene_genome` (`genome_name`),
KEY `gene_gene_category` (`gene_category`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

SELECT a.genome_name, a.gene_id,
cats.gene_category,
(
SELECT COUNT(*)
FROM geneHomology ab
JOIN gene b
ON b.genome_name = ab.homolog_genome_name
AND b.gene_id = ab.homolog_gene_id
WHERE ab.genome_name = a.genome_name
AND ab.gene_id = a.gene_id
AND b.gene_category = cats.gene_category
) cx
FROM gene a
CROSS JOIN
(
SELECT 'Normal' AS gene_category
UNION ALL
SELECT 'Upregulated' AS gene_category
UNION ALL
SELECT 'Downregulated' AS gene_category
) cats
LIMIT 100
This will remove filesort from your plan.
If you have a table with all possible gene_categories, replace the cats with it.

From what you've posted here, I would reccomend a minor bit of denormalisation and put gene_category into geneHomolgy. You can then get rid of the join entirely and you can create an index on your consider_homolog + GROUP BY fields.

First remove the reference to genome_name from the WHERE part of the query - if both gene.gene_id and gene.genome_name are unique then here is a clear functional dependency here which is confusing the issue somewhat - the number/number join will be marginally mroe efficient that the text/text join.
Looking at the plan it rather implies you've already got an index on geneHomology.hit_gene_id . If this is the case then there's not much scope for making the query go faster without schema changes. However a key length of 54 suggests you've got a lot of stuff in that index which should not be there. Trimming this down to just hit_gene_id and consider_homolog will help a little with the performance, but the limiting factor is that there does not seem any way to avoid the full table scan on gene unless there are other functional dependencies in there.
How quickly does it take to complete a 'SELECT * FROM gene' ? How many records in ene_homology?
It looks like geneHomology decomposes a N:M relationship between gene and gene (itself) and applies labels.
If the number of values in homolog_genome_name is relatively small you might consider decomposing this into gene using bitmap field. Or possibly denormalise the relationship into a set of 1:1 mappings. Alternatively you could enumerate the homolog clusters.

Related

Change foreign key without losing data in column

I've checked google, but I haven't found a way to preserve data while changing a foreign key on a table.
I have two tables, User Events and User Sports
Table User Events
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| date | date | YES | | NULL | |
| description | text | YES | | NULL | |
| user_id | int(10) unsigned | YES | MUL | NULL | |
| sport_id | int(10) unsigned | YES | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| deleted_at | timestamp | YES | MUL | NULL | |
+--------------+------------------+------+-----+---------+----------------+
Table User Sports
+------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(191) | NO | | NULL | |
| default_sport_id | int(10) unsigned | YES | UNI | NULL | |
| user_id | int(11) | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| deleted_at | timestamp | YES | | NULL | |
+------------------+------------------+------+-----+---------+----------------+
Before creating User Sports table, in table User Events I had foreign sport_id from Sports table.
Now, when I want to change that column to be foreign key from Sports to User Sports table I'm getting this message on php artisan migrate:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails
The migration works if I drop the column sport_id from User Events but I don't want data loss.
Here is my migration:
public function up()
{
Schema::table('user_events', function (Blueprint $table) {
$table->dropForeign('event_sport_id');
});
Schema::table('user_events', function (Blueprint $table) {
$table->foreign('sport_id')
->references('default_sport_id')
->on('user_sports')
->onDelete('set null');
});
}
Can someone point me in the right direction?
Thanks
You must pass an array not a string to the method dropForeign: $table->dropForeign(['event_sport_id']);

Laravel Eloquent relation depending on type of item

I have model Product, it has 2 types: Lamps and Bulbs. A lamp have set of attributes that differs from a bulb, so I have 2 another models Lamp and Bulb which represent set of attributes. What type of relation from Product to attribute model should I implement in this situation?
I've been trying one-to-one relation, but in my situation this second "one" differs from product's type.
I've been thinking of EAV pattern, but I don't want tons of joins in my architecture right now because I don't need more than these two types of item.
What would you suggest?
UPD1: here are the tables (simplified):
mysql> show columns from products;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(127) | NO | | NULL | |
| price | double | NO | | NULL | |
| old_price | double | NO | | NULL | |
| category_id | int(11) | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql> show columns from lamps;
+------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| product_id | int(11) | NO | | NULL | |
| width | int(11) | NO | | NULL | |
| height | int(11) | NO | | NULL | |
| length | int(11) | NO | | NULL | |
| weight | int(11) | NO | | NULL | |
+------------+---------+------+-----+---------+----------------+
7 rows in set (0.00 sec)
mysql> show columns from bulbs;
+------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| product_id | int(11) | NO | | NULL | |
| voltage | int(11) | NO | | NULL | |
| power | int(11) | NO | | NULL | |
| base | int(11) | NO | | NULL | |
| type | int(11) | NO | | NULL | |
+------------+---------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
UPD2: I understand that I can use two foreign keys in products table and set up only one of them for each record, but is there some more elegant scheme for this situation?

how to select not-null values from Oracle (optimized method)

how can I select not null values from table ...
lets image table as follows:
master_id | date_update | name | dpt | channel | source | active
---------------------------------------------------------------------------
1 | 1/2/2015 15:43:21 | NULL | NULL | NULL | NULL | y
1 | 1/2/2015 15:43:21 | NULL | FIN | NULL | NULL | n
1 | 1/2/2015 15:40:16 | Elvis | NULL | NULL | NULL | n
1 | 1/2/2015 15:26:38 | NULL | NULL | CH1 | NULL | n
1 | 1/2/2015 14:57:02 | NULL | NULL | NULL | S1 | n
5 | 2/2/2015 15:28:02 | NULL | NULL | CH2 | NULL | y
5 | 1/2/2015 10:13:01 | Sarah | NULL | NULL | NULL | n
The result I would like to get is:
master_id | date_update | name | dpt | channel | source | active
---------------------------------------------------------------------------
1 | 1/2/2015 15:43:21 | Elvis | FIN | CH1 | S1 | y
5 | 2/2/2015 15:28:02 | Sarah | NULL | CH2 | NULL | y
You can notice, that DATE_UPDATE and ACTIVE column is the latest one ...
Which method is the most optimized one?
I tried the combination of listagg (to merge rows into one) and then get the last informations via row_number() over() or max() over() but I am not sure if it is the best performance solution ... joins are also not the best solution (because there are 17 columns I need to merge) ..
The Oracle MAX() aggregate function should ignore NULL values, meaning it should pick up on the non NULL value in each master_id group as being the "max" for that column/group.
SELECT master_id, MAX(date_update), MAX(name), MAX(dpt), MAX(channel), MAX(source),
MAX(active)
FROM image
GROUP BY master_id

Laravel 5 Eloquent ORM - Many to Many through Many to Many

I'm working on a rather complex Users system that requires the ability to grant access privileges to either individuals or entire groups. For example, you could grant Jane Doe access to moderate the Message Board, or all users of the Communications Group to send emails, moderate the message board, and post events (all users assigned to the group are granted access to those privileges when added).
Rather than strictly track individual privileges for each user, I want to grant access to a feature first based on whether or not the user belongs to a group containing that privilege. If they don't, I then want to check to see if they are granted individual access (privilege_user pivot table).
Basically, I want something like this:
// 1 = Message Board Moderator
// See if any of the user's groups contain this privilege -
$hasAccess = Auth::user()->groups->privileges->contains(1);
Here is my table structure:
Users
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| username | varchar(80) | NO | | NULL | |
| email | varchar(120) | NO | | NULL | |
| first_name | varchar(20) | NO | MUL | NULL | |
| last_name | varchar(45) | NO | MUL | NULL | |
| password | varchar(140) | NO | | NULL | |
| active | tinyint(1) | NO | | NULL | |
| remember_token | varchar(100) | NO | | NULL | |
| last_login | timestamp | YES | | NULL | |
| last_login_ip | varchar(45) | YES | | NULL | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| deleted_at | timestamp | YES | | NULL | |
+----------------+------------------+------+-----+---------------------+----------------+
Groups (table: user_groups)
+-------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| slug | varchar(255) | NO | | NULL | |
| description | text | NO | | NULL | |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
+-------------+------------------+------+-----+---------------------+----------------+
User Groups Pivot (table: user_user_group)
+---------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+-------+
| user_id | int(10) unsigned | NO | MUL | NULL | |
| user_group_id | int(10) unsigned | NO | MUL | NULL | |
+---------------+------------------+------+-----+---------+-------+
Privileges (table: privleges)
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| slug | varchar(255) | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
Privileges User Group Pivot (table: privilege_user_group)
+---------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+-------+
| privilege_id | int(10) unsigned | NO | MUL | NULL | |
| user_group_id | int(10) unsigned | NO | MUL | NULL | |
+---------------+------------------+------+-----+---------+-------+
Was disappointed that nobody chimed in here on SO but fortunately I was able to find some great help at Laracasts.com.
I went with Zizaco/entrust, which does exactly what I was describing. The only part lacking is answering the question "does this User have a Permission" without the user being assigned to a Group, but that is easy to accomplish with Eloquent. What entrust does do is answer the question "Does this User have access to this Permission through a Group?" And that's what I was after.

Oracle query execution plan

I am little confused over the execution plan of an Oracle query. This is in Oracle Enterprise Edition 11.2.0.1.0 on platform IBM AIX 6.1. I have a table TEST1 (1 million rows) and another table TEST2 (50,000 rows). Both tables have identical columns. There is a view created as a union of these 2 tables. I am firing a query on this view, with an indexed column in the WHERE clause. What I could find is that the index is not used and a full table scan is resulted. With a slight modification of the query, it started using the index. I am wondering how this particular change can result in the plan change.
Please find the complete DDL + DML below. I have given simplified example. Actual schema and requirements are bit more complex. In fact the query in question is dynamically constructed and executed by an OCI code generator. My intention here is not to get alternatives, but to really understand what could be the logical reasoning behind the plan change (between, I am an application programmer and not a database administrator). Your help is much appreciated.
DROP TABLE TEST1 CASCADE CONSTRAINTS ;
DROP TABLE TEST2 CASCADE CONSTRAINTS ;
CREATE TABLE TEST1
(
ID NUMBER(20) NOT NULL,
NAME VARCHAR2(40),
DAY NUMBER(20)
)
PARTITION BY RANGE (DAY)
(
PARTITION P001 VALUES LESS THAN (2),
PARTITION P002 VALUES LESS THAN (3),
PARTITION P003 VALUES LESS THAN (4),
PARTITION P004 VALUES LESS THAN (5),
PARTITION P005 VALUES LESS THAN (6),
PARTITION P006 VALUES LESS THAN (7),
PARTITION P007 VALUES LESS THAN (8),
PARTITION P008 VALUES LESS THAN (9),
PARTITION P009 VALUES LESS THAN (10),
PARTITION P010 VALUES LESS THAN (11),
PARTITION P011 VALUES LESS THAN (12),
PARTITION P012 VALUES LESS THAN (13),
PARTITION P013 VALUES LESS THAN (14),
PARTITION P014 VALUES LESS THAN (15),
PARTITION P015 VALUES LESS THAN (16),
PARTITION P016 VALUES LESS THAN (17),
PARTITION P017 VALUES LESS THAN (18),
PARTITION P018 VALUES LESS THAN (19),
PARTITION P019 VALUES LESS THAN (20),
PARTITION P020 VALUES LESS THAN (21),
PARTITION P021 VALUES LESS THAN (22),
PARTITION P022 VALUES LESS THAN (23),
PARTITION P023 VALUES LESS THAN (24),
PARTITION P024 VALUES LESS THAN (25),
PARTITION P025 VALUES LESS THAN (26),
PARTITION P026 VALUES LESS THAN (27),
PARTITION P027 VALUES LESS THAN (28),
PARTITION P028 VALUES LESS THAN (29),
PARTITION P029 VALUES LESS THAN (30),
PARTITION P030 VALUES LESS THAN (31)
) ;
CREATE INDEX IX_ID on TEST1 (ID) INITRANS 4 STORAGE(FREELISTS 16) LOCAL
(
PARTITION P001,
PARTITION P002,
PARTITION P003,
PARTITION P004,
PARTITION P005,
PARTITION P006,
PARTITION P007,
PARTITION P008,
PARTITION P009,
PARTITION P010,
PARTITION P011,
PARTITION P012,
PARTITION P013,
PARTITION P014,
PARTITION P015,
PARTITION P016,
PARTITION P017,
PARTITION P018,
PARTITION P019,
PARTITION P020,
PARTITION P021,
PARTITION P022,
PARTITION P023,
PARTITION P024,
PARTITION P025,
PARTITION P026,
PARTITION P027,
PARTITION P028,
PARTITION P029,
PARTITION P030
) ;
CREATE TABLE TEST2
(
ID NUMBER(20) PRIMARY KEY NOT NULL,
NAME VARCHAR2(40),
DAY NUMBER(20)
) ;
CREATE OR REPLACE VIEW TEST_V AS
SELECT
ID, NAME, DAY
FROM
TEST1
UNION
SELECT
ID, NAME, DAY
FROM
TEST2 ;
begin
for count in 1..1000000
loop
insert into test1 values(count, 'John', mod(count, 30) + 1) ;
end loop ;
end ;
/
begin
for count in 1000000..1050000
loop
insert into test2 values(count, 'Mary', mod(count, 30) + 1) ;
end loop ;
end ;
/
commit ;
set lines 300 ;
set pages 1000 ;
-- Actual query
explain plan for
SELECT Key FROM
(
WITH recs AS
(
SELECT * FROM TEST_V WHERE ID = 70000
)
(
SELECT 1 AS Key FROM recs WHERE NAME = 'John'
)
UNION
(
SELECT 2 AS Key FROM recs WHERE NAME = 'Mary'
)
) ;
select * from table(dbms_xplan.display()) ;
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | TempSpc | Cost (%CPU) | Time | Pstart | Pstop |
------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1611K | 4721K | | 13559 (1) | 00:02:43 | | |
| 1 | VIEW | | 1611K | 4721K | | 13559 (1) | 00:02:43 | | |
| 2 | TEMP TABLE TRANSFORMATION | | | | | | | | |
| 3 | LOAD AS SELECT | SYS_TEMP_0FD9D6610_34D3B6C | | | | | | | |
|* 4 | VIEW | TEST_V | 805K | 36M | | 10403 (1) | 00:02:05 | | |
| 5 | SORT UNIQUE | | 805K | 36M | 46M | 10403 (8) | 00:02:05 | | |
| 6 | UNION-ALL | | | | | | | | |
| 7 | PARTITION RANGE ALL | | 752K | 34M | | 721 (1) | 00:00:09 | 1 | 30 |
| 8 | TABLE ACCESS FULL | TEST1 | 752K | 34M | | 721 (1) | 00:00:09 | 1 | 30 |
| 9 | TABLE ACCESS FULL | TEST2 | 53262 | 2496K | | 68 (0) | 00:00:01 | | |
| 10 | SORT UNIQUE | | 1611K | 33M | 43M | 13559 (51) | 00:02:43 | | |
| 11 | UNION-ALL | | | | | | | | |
|* 12 | VIEW | | 805K | 16M | | 1429 (1) | 00:00:18 | | |
| 13 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6610_34D3B6C | 805K | 36M | | 1429 (1) | 00:00:18 | | |
|* 14 | VIEW | | 805K | 16M | | 1429 (1) | 00:00:18 | | |
| 15 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6610_34D3B6C | 805K | 36M | | 1429 (1) | 00:00:18 | | |
------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("ID"=70000)
12 - filter("NAME"='John')
14 - filter("NAME"='Mary')
-- Modified query (only change is absence of outermost SELECT)
explain plan for
WITH recs AS
(
SELECT * FROM TEST_V WHERE ID = 70000
)
(
SELECT 1 AS Key FROM recs WHERE NAME = 'John'
)
UNION
(
SELECT 2 AS Key FROM recs WHERE NAME = 'Mary'
) ;
select * from table(dbms_xplan.display()) ;
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | Pstart | Pstop |
-----------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 88 | 6 (67) | 00:00:01 | | |
| 1 | TEMP TABLE TRANSFORMATION | | | | | | | |
| 2 | LOAD AS SELECT | SYS_TEMP_0FD9D6611_34D3B6C | | | | | | |
| 3 | VIEW | TEST_V | 2 | 96 | 4 (50) | 00:00:01 | | |
| 4 | SORT UNIQUE | | 2 | 96 | 4 (75) | 00:00:01 | | |
| 5 | UNION-ALL | | | | | | | |
| 6 | PARTITION RANGE ALL | | 1 | 48 | 1 (0) | 00:00:01 | 1 | 30 |
| 7 | TABLE ACCESS BY LOCAL INDEX ROWID | TEST1 | 1 | 48 | 1 (0) | 00:00:01 | 1 | 30 |
|* 8 | INDEX RANGE SCAN | IX_ID | 1 | | 1 (0) | 00:00:01 | 1 | 30 |
| 9 | TABLE ACCESS BY INDEX ROWID | TEST2 | 1 | 48 | 1 (0) | 00:00:01 | | |
|* 10 | INDEX UNIQUE SCAN | SYS_C001242692 | 1 | | 1 (0) | 00:00:01 | | |
| 11 | SORT UNIQUE | | 4 | 88 | 6 (67) | 00:00:01 | | |
| 12 | UNION-ALL | | | | | | | |
|* 13 | VIEW | | 2 | 44 | 2 (0) | 00:00:01 | | |
| 14 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6611_34D3B6C | 2 | 96 | 2 (0) | 00:00:01 | | |
|* 15 | VIEW | | 2 | 44 | 2 (0) | 00:00:01 | | |
| 16 | TABLE ACCESS FULL | SYS_TEMP_0FD9D6611_34D3B6C | 2 | 96 | 2 (0) | 00:00:01 | | |
-----------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
8 - access("ID"=70000)
10 - access("ID"=70000)
13 - filter("NAME"='John')
15 - filter("NAME"='Mary')
quit ;
thanks & regards,
Reji
I can not reproduce this in 11.2.0.3, I don't think there is a logical explanation for this behavior other than: you hit a bug, that apparently is solved in 11.2.0.3.
One thing that jumped immediately in my eye is the lack of object statistics and - if your output was complete - the fact that OPTIMIZER_DYNAMIC_SAMPLING is set to 0. You could try to reproduce with OPTIMIZER_DYNAMIC_SAMPLING=2. In that case the dynamic sampler kicks in if the object statistics are missing. BTW: don't use this feature instead of correct optimizer statistics. More info about dynamic sampling Dynamic sampling and its impact on the Optimizer
In your - nice documented - question and script/test case you try to make use of append and nologging. This only works for bulk inserts, not for row inserts with values. What would happen is for every insert: push-up the highwater mark and dump a full block of data in the free block, in your case that would have only 1 row .... Luckily, the database ignores this instruction.
Before you fire SQL to a table, make sure that you give it optimizer statistics. This will certainly help your case.

Resources