1

Description: Voici un exemple de démonstration du problème de performance.Les performances de la sécurité au niveau de la ligne (RLS) sont nettement plus faibles dans PostgreSQL.

Nous avons d'abord créé deux tables, activé la sécurité au niveau de la ligne et créé la politique.

Tableau Définition:

create table sample_schema.sample_table1(ID numeric(38) PRIMARY KEY NOT NULL, 
       tenant_id VARCHAR(255) NOT NULL, 
       Description VARCHAR(255) 
     ); 

create table sample_schema.sample_table2(ID2 numeric(38) PRIMARY KEY NOT NULL, 
       tenant_id VARCHAR(255) NOT NULL, 
       table1_id numeric (38), 
       Description2 VARCHAR(255) 
     );  

création d'index:

CREATE UNIQUE INDEX sample_table1_idx1 ON sample_schema.sample_table1(tenant_id,id);    

Activer la sécurité au niveau de la ligne:

ALTER TABLE sample_schema.sample_table1 ENABLE ROW LEVEL SECURITY; 

créer rôle:

CREATE ROLE tenant_grp_role_p_id;  

Créer une stratégie: Je veux une politique de sélection des données où la valeur de la colonne de tenant_id a un rôle qui est le même que l'utilisateur qui a connecté

CREATE POLICY Tenant_Roles ON sample_schema.sample_table1 TO tenant_grp_role_p_id USING ((tenant_id) IN (SELECT rolname FROM pg_roles WHERE pg_has_role(current_user, oid, 'member'))); 

créer des données d'échantillon.

insert into sample_schema.sample_table1 values (1,'user1_tenant1',1,'Table1 Data'); 
insert into sample_schema.sample_table2 values (2,'user1_tenant1',1,'Table2 Data'); 

Problème: La requête ci-dessous n'utilise pas l'index primary_key.

SELECT * FROM sample_schema.sample_table1 ST1, sample_schema.sample_table2 T2 WHERE ST1.id = ST2.table1_id AND ST1.id = 1;  

Question: Si je désactive RLS puis index de clé primaire est utilisé .Pourquoi est-il pas en recherche automatique index de clé primaire lorsque RLS est activée? A. Si je désactive la sécurité au niveau de la ligne et exécute la requête ci-dessus, il utilise l'index.
B.below est le plan d'explication Sortie lorsque la sécurité de bas niveau est désactivée. C. Si j'active la sécurité de bas niveau et exécute la requête, elle n'utilise pas d'index.
et ci-dessous est le plan d'explication Sortie lorsque la sécurité de bas niveau est activée.

Nested Loop (cost=1.03..946.65 rows=79 width=1129) -> Seq Scan on sample_table2 st2 (cost=0.00..10.88 rows=1 width=1092) Filter: (table1_id = '1'::numeric) -> Subquery Scan on st1 (cost=1.03..934.98 rows=79 width=37) 
    Filter: (st1.id = '1'::numeric)  -> Hash Join (cost=1.03..738.11 rows=15750 width=37)    Hash Cond: ((st1_1.tenant_id)::name = pg_authid.rolname)    -> Seq Scan on sample_table1 st1_1 (cost=0.00..578.00 rows=31500 width=37)    -> Hash (cost=1.01..1.01 rows=1 width=68)     -> Seq Scan on pg_authid (cost=0.00..1.01 rows=1 width=68)       Filter: pg_has_role("current_user"(), oid, 'member'::text); 

S'il vous plaît aidez-moi à résoudre ce problème ..

+1

Veuillez conserver la mise en forme et l'indentation des plans d'exécution. La façon dont vous les avez ajoutés à votre question les rend inutiles. –

+0

Ceci est la même que cette question: http://stackoverflow.com/questions/41169479/postgresql-multi-tenant-mode-not-using-index#comment69569639_41169479 –

Répondre

2

Voir this message thread sur la liste de diffusion pgsql général pour plus de détails.

J'ai récemment appliqué RLS à plusieurs grandes (plusieurs millions de lignes) tables dans ma base de données 9.5 et remarqué que les requêtes sur une seule table grande RLS protégées fonctionnent bien mais les requêtes qui rejoignent plusieurs grandes RLS tables protégées fonctionnent très pauvrement. Le plan d'explication indique que l'optimiseur analyse la totalité de la table pour appliquer la règle RLS avant d'exécuter la jointure de clé primaire, ce qui réduit les résultats de la requête à une seule ligne de chaque table. De toute évidence, les performances seraient meilleures si elles effectuaient la jointure avant la vérification de la politique.D'après ce que je peux comprendre, l'implémentation RLS s'efforce d'exécuter les vérifications de politique avant les vérifications de prédicat fournies par l'utilisateur afin d'éviter les données protégées fuyant .

Et les réponses:

cas d'inscription avec RLS ne sont pas optimisés très bien pour le moment. Il ya travail à pied pour améliorer cela - voir https://www.postgresql.org/message-id/flat/8185.1477432701%40sss.pgh.pa.us - mais il ne sera pas en production avant v10.

Et:

Vous pouvez utiliser une vue de barrière de sécurité qui est détenue par le même utilisateur que les tables sous sont la propriété, qui contournera RLS sur les tables eux-mêmes et donc vous » Vous devez implémenter les qualificatifs appropriés dans la vue de la barrière de sécurité.

Vous pouvez donc attendre PG10 ou utiliser un security barrier view à la place. Ce blog explique également pourquoi Postgres n'essaie pas de combiner (et optimiser) les conditions de sécurité et les conditions spécifiées par l'utilisateur: une fonction personnalisée peut être utilisée pour filtrer des valeurs qui seraient autrement cachées à l'utilisateur.

Pour créer un tel point de vue, il suffit d'ajouter à la définition with (security_barrier):

rhaas=# create or replace view unclassified_emp with (security_barrier) as 
     select * from emp where organization <> 'CIA'; 
CREATE VIEW 

Il y a plus d'informations dans this detailed blog post aussi.