if locked statistics on synonym of table A, gather statistics on the table A throws an error Oracle in 18c? - oracle18c

I have Oracle 18c db.
Suppose I have a PUBLIC SYNONYM S_Customer for table database1.Customer
CREATE OR REPLACE PUBLIC SYNONYM S_Customer for database1.Customer;
If locked statistics on S_Customer, gather statistics on the database1.Customer throws an error Oracle in 18c?
According to https://oraclespin.com/2008/10/09/how-to-lockunlock-statistics-on-a-table/
, if I lock statistics on a table, gather statistics on locked table throws an error.
I'm wondering whether locking the statistic on the synonym of a table will also throws the same error when I gather statistics of the table ( instead of synonym ) or not.

You cannot lock the statistics of a synonym, only of a table. The name of the procedure is quite clear: LOCK_TABLE_STATS, the documentation says "table", and a quick test confirms it:
CREATE TABLE customer (id NUMBER, name VARCHAR2(50));
CREATE SYNONYM s_customer FOR customer;
exec dbms_stats.lock_table_stats(user, 's_customer');
ORA-20000: TABLE "SO"."S_CUSTOMER" does not exist or insufficient privileges

Related

Redshift: Truncating Table Created by another user

I'm trying to truncate a table in redshift but it's throwing the following error -
SQL Error [500310] [42501]: Amazon Invalid operation: must
be owner of relation table;
I have already granted all the privileges on the table to the user. As checked through the online documentation for redshift, I can't grant the truncate table access explicitly like the way it's enabled now in PostgreSQL. Is there a way or a best practice to handle this scenario?
As you say only the table owner or a superuser can truncate a table. There are several options.
Change the table to be owned by the user that needs to truncate but this may not meet other constraints
Alter table to current user, truncate, and alter it back to the previous user (requires DROP permission)
Drop and recreate the table but this may break dependencies
Make a table LIKE the original, perform an ALTER TABLE APPEND to this new table, and then drop the new table (some restrictions like no identity columns)

Foreign table inserts don't use the remote sequence

I have a set of applications accessing two different PostgreSQL 9.6 DBs on the same server. Due to some application limitations, one application accesses a handful of tables via FDW in one DB to the other.
Something like this:
DB1.fdw_table_a -> DB2.table_a
fdw_table_a is only used for inserts of log data. This table has an id column, which is a bigint sequence. The sequence exists in DB1 (on the foreign table) and in DB2 (the "real" table). This works as it should and all is well.
Now there's a need to have another application (again with limited access capabilities) perform inserts into the "real" table, DB2.table_a. In testing, I can see some inconsistencies in the id column, but no obvious issues have appeared.
I can see in the customer-facing environments that the DB1 FDW sequence is used as expected, but when inserts start directly on the DB2 'real' table, that sequence will start at 1 (as it has never been used).
Are there other things we should be considering in this environment?
Are there some issues that could arise from overlap in these two sequences inserting into the table?
The sequence only gets used if you omit the id column in the INSERT statement. But postgres_fdw will never omit a column, as you can see from the execution plan.
One way to solve the problem is to use a foreign table that does not contain the id column. Then any insert into that foreign table will use the sequence to populate that column.
The following plan from 2014 is still valid today.
=# CREATE SEQUENCE seq;
CREATE SEQUENCE
=# CREATE VIEW seq_view AS SELECT nextval('seq') as a;
CREATE VIEW
=# CREATE EXTENSION postgres_fdw;
CREATE EXTENSION
=# CREATE SERVER postgres_server
-# FOREIGN DATA WRAPPER postgres_fdw
-# OPTIONS (host 'localhost', port '5433', dbname 'postgres');
CREATE SERVER
=# CREATE USER MAPPING FOR PUBLIC SERVER postgres_server OPTIONS (password '');
CREATE USER MAPPING
=# CREATE FOREIGN TABLE foreign_seq_table (a bigint)
-# SERVER postgres_server OPTIONS (table_name 'seq_view');
CREATE FOREIGN TABLE
=# CREATE FUNCTION foreign_seq_nextval() RETURNS bigint AS
-# 'SELECT a FROM foreign_seq_table;' LANGUAGE SQL;
CREATE FUNCTION
=# CREATE TABLE tab (a int DEFAULT foreign_seq_nextval());
CREATE TABLE
=# INSERT INTO tab VALUES (DEFAULT), (DEFAULT), (DEFAULT);
INSERT 0 3
=# SELECT * FROM tab;
a
----
9
10
11
(3 rows)
https://paquier.xyz/postgresql-2/global-sequences-with-postgres_fdw-and-postgres-core/

temp tables in postgresql

I'm coming from a background in SQL Server where I would create temp tables using the:
select id
into #test
from table A
I've just moved into a PostGresql environment and I was hoping I could do the same, but I'm getting a syntax error. I did a search and it seems like you have to do a Create Table statement.
Is it not possible to easily create temp tables in Postgres?
Postgres supports SELECT INTO, so this should work fine:
SELECT id
INTO TEMP TABLE test
FROM a
You can also use CREATE TABLE AS:
CREATE TEMP TABLE test AS
SELECT id FROM a
This version is generally preferred, as the CREATE statement provides additional options, and can also be used in PL/pgSQL functions (where the SELECT INTO syntax has been hijacked for variable assignment).

Postgresql foreign tables exists clause

I'm running two different postgres 9.3 instances (one for production, one for development/testing). I want to copy a subset of a table in production into development.
Let's say then that the table I want to copy is defined as
CREATE TABLE users (user_id varchar PRIMARY KEY, other_stuff varchar);
and the subset I want to copy is all the users who have user_id in a cached table (on production), which is a much smaller table than the users table
CREATE TABLE user_id_subset (user_id varchar PRIMARY KEY);
I've set up some foreign tables on my development db to access these two tables (named foreign_users, and foreign_user_id_subset respectively), and I want to do a query like:
INSERT INTO development_users (user_id, other_stuff)
SELECT user_id, other_stuff FROM foreign_users f
WHERE EXISTS (
SELECT 1 FROM foreign_user_id_subset ss
WHERE ss.user_id=f.user_id)
This query works, but I'm worried about performance. The result of an explain gives me something like this:
'Insert on development_users (cost=262.01..284.09 rows=138 width=272)'
' -> Hash Join (cost=262.01..284.09 rows=138 width=272)'
' Hash Cond: ((f.user_id)::text = (cache.user_id)::text)'
' -> Foreign Scan on foreign_users f (cost=100.00..118.28 rows=276 width=272)'
' -> Hash (cost=159.52..159.52 rows=200 width=32)'
' -> HashAggregate (cost=157.52..159.52 rows=200 width=32)'
' -> Foreign Scan on foreign_user_id_subset (cost=100.00..153.86 rows=1462 width=32)'
What I think is happening is that my development db sends the request to my production db, which creates the temp hash of foreign_user_id_subset (user_id_subset on production) and does the hash check on production. This way, the only thing that gets sent across the wire (between the databases) is the initial request, and then the result of the select query. Is this true?
An alternative idea would be to create a 'temp' (can't be a true TEMP table b/c I need a foreign table) of the result of this request on my production database, and then build a foreign table and just do a SELECT * from development on the foreign table.
(It should be noted that my production database is a much pricier/performant RDS instance than my development database)
To answer my own question:
I implemented the alternative idea described above: generating the table in production containing only the results of the EXISTS query, and then created a foreign table in development to reference that table. Then to create the subset table, I just did an 'INSERT INTO ...SELECT * FROM ...'.
The timing was dramatically faster using this than the original method posted.
Time to create table on production:
Total runtime: 204.838 ms
Time to insert into development database: Total runtime: 1564.444 ms
And to do the original method:
it's unacceptably slow, taking > 10 minutes to achieve the same result as above (I didn't even wait for the explain analyze to finish)
I don't know a better way to determine lower-level instructions past what the planner provides, but I'm lead to believe that the original method performs a sequential scan (made by repeatedly scanning chunks of the foreign table) and performs the hash comparison on the development database.

PostgreSQL syntax error related to INSERT and/or WITH. Occurs in 8.4 but not 9.1. Ideas?

Here is some SQL for PostgreSQL (I know it's a silly query; I've boiled the original query down to the simplest broken code):
CREATE TABLE entity (
id SERIAL PRIMARY KEY
);
WITH new_entity
AS (INSERT INTO entity DEFAULT VALUES
RETURNING id
)
SELECT id FROM new_entity;
Here it is running on PostgreSQL 9.1:
psql:../sandbox/test.sql:3: NOTICE: CREATE TABLE will create implicit sequence "entity_id_seq" for serial column "entity.id"
psql:../sandbox/test.sql:3: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "entity_pkey" for table "entity"
CREATE TABLE
id
----
1
(1 row)
Here it is not running on PostgreSQL 8.4:
psql:../sandbox/test.sql:3: NOTICE: CREATE TABLE will create implicit sequence "entity_id_seq" for serial column "entity.id"
psql:../sandbox/test.sql:3: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "entity_pkey" for table "entity"
CREATE TABLE
psql:../sandbox/test.sql:9: ERROR: syntax error at or near "INSERT"
LINE 2: AS (INSERT INTO entity DEFAULT VALUES
Obviously, the table creation goes fine in both cases, but it wipes out on the second query in PostgreSQL 8.4. From this error message I am unable to gather exactly what the problem is. I don't know what it is that 9.1 has and 8.4 doesn't have that could result in this syntax error. It's hilariously hard to google it. I am approaching the level of desperation required to trawl through the pages of PostgreSQL release notes between 8.4 and 9.1 and finding out if anything related to WITH … AS or INSERT … RETURNING was changed or added, but before I go there I am hoping one of you has the experience and/or godly google-fu to help me out here.
Data-modifying statements in WITH were introduced in Postgres 9.1