registros - Cómo manejar una gran cantidad de banderas para un registro de SQL
manual de postgresql 10 en español pdf (8)
Necesito consejos sobre cómo manejar un conjunto relativamente grande de banderas en mi tabla SQL2k8.
Dos preguntas, tengan paciencia, por favor :)
Digamos que tengo 20 banderas que me gustaría almacenar para un registro.
Por ejemplo:
CanRead = 0x1 CanWrite = 0x2 CanModify = 0x4 ... y así sucesivamente a la bandera final 2 ^ 20
Ahora, si configuro la siguiente combinación de un registro: Permisos = CanRead | Puede escribir
Puedo verificar fácilmente si ese registro ha requerido permiso haciendo WHERE (Permisos y CanRead) = CanRead
Eso funciona.
Pero, también me gustaría recuperar todos los registros que pueden escribir O modificar.
Si publico WHERE (Permisos & (CanWrite | CanModify)) = (CanWrite | CanModify) Obviamente no obtendré mi registro que tiene permisos establecidos en CanRead | Puede escribir
En otras palabras, ¿cómo puedo encontrar registros que coincidan con NINGUNO de los indicadores en mi máscara que estoy enviando al procedimiento?
Segunda pregunta, ¿qué rendimiento tiene en SQL 2008? ¿Sería realmente mejor crear campos de 20 bits?
Gracias por tu ayuda
¿No es tan simple como ...
WHERE (Permissions & ( CanWrite | CanModify )) > 0
... como cualquier ''bit'' se establece en 1 dará como resultado un valor distinto de cero para el operador ''&''.
Es tarde en el día y estoy a punto de irme a casa, por lo que mi cerebro podría estar funcionando de manera ineficiente.
DÓNDE (Permisos y CanWrite) = CanWrite O (Permisos y CanModificar) = CanModify
creo
Haga esto solo si también está consultando por alguna otra tecla.
No hagas esto si consultas por combinaciones de banderas. Un índice en contra de esta columna no lo ayudará en general. Estará restringido a escaneos de tabla.
No, eso no funcionará.
Enviaré solo una máscara para el procedimiento
Algo como @filter que en C # llene con @filter = CanModify | Puede escribir
Entonces, el procedimiento obtiene el valor OR-ed como un filtro.
Oh, y por cierto, NO es un modelo de permiso, lo estoy usando solo como un ejemplo.
Realmente tengo alrededor de 20 banderas únicas que mi objeto puede tener.
Qué pasa
WHERE (Permissions & CanWrite) = CanWrite
OR (Permissions & CanModify) = CanModify
?
Supongo que su columna Permisos es una Int. Si es así, te animo a jugar con el código de muestra que proporciono a continuación. Esto debería darle una indicación clara de cómo funciona la funcionalidad.
Declare @Temp Table(Permission Int, PermissionType VarChar(20))
Declare @CanRead Int
Declare @CanWrite Int
Declare @CanModify Int
Select @CanRead = 1, @CanWrite = 2, @CanModify = 4
Insert Into @Temp Values(@CanRead | @CanWrite, ''Read,write'')
Insert Into @Temp Values(@CanRead, ''Read'')
Insert Into @Temp Values(@CanWrite, ''Write'')
Insert Into @Temp Values(@CanModify | @CanWrite, ''Modify, write'')
Insert Into @Temp Values(@CanModify, ''Modify'')
Select *
From @Temp
Where Permission & (@CanRead | @CanWrite) > 0
Select *
From @Temp
Where Permission & (@CanRead | @CanModify) > 0
Cuando usa lógica y, obtendrá un número con el conjunto de 1 apropiadamente basado en su condición. Si nada coincide, el resultado será 0. Si 1 o más condiciones coinciden, el resultado será mayor que 0.
Dejame mostrarte un ejemplo.
Supongamos que CanRead = 1, CanWrite = 2 y CanModify = 4. Las combinaciones válidas son:
Modify Write Read Permissions
------ ----- ---- -----------
0 0 0 Nothing
0 0 1 Read
0 1 0 Write
0 1 1 Read, Write
1 0 0 Modify
1 0 1 Modify, Read
1 1 0 Modify, Write
1 1 1 Modify, Write, Read
Ahora, supongamos que quiere probar para Leer o Modificar. Desde su aplicación, pasaría (CanRead | CanModify). Esto sería 101 (en binario).
Primero, probemos esto contra una fila en la tabla que el ÚNICO ha leído.
001 (Row from table)
& 101 (Permissions to test)
------
001 (result is greater than 0)
Ahora, probemos contra una fila que solo tiene escritura.
010 (Row from table)
& 101 (Permission to test)
------
000 (result = 0)
Ahora pruébelo contra la fila que tiene los 3 permisos.
111 (Row from table)
& 101 (Permission to test)
------
101 (result is greater than 0)
Espero que pueda ver que si el resultado de la operación AND arroja un valor = 0, entonces ninguno de los permisos probados se aplica a esa fila. Si el valor es mayor que 0, entonces al menos una fila está presente.
No a eso. Es como guardar una cadena de CSV en un campo memo y anular el propósito de una base de datos.
Use un valor booleano (bit) para cada indicador. En esta muestra específica encontrará todo lo que puede leer y puede escribir o modificar:
WHERE CanRead AND (CanWrite OR CanModify)
Simple SQL puro sin hacks inteligentes. Los 7 bits extra que estás desperdiciando por cada bandera no valen la pena.
Sería considerablemente mejor tener un modelo de permisos diferente.
20 banderas me indicarán que se requiere un replanteamiento, la mayoría de los sistemas de archivo pueden funcionar con 12 indicadores básicos y ACLS, tal vez con una tabla separada que simplemente otorga permisos o grupos de objetos o accesadores para permitir un control diferente.
Esperaría que un select sea más rápido para tener 20 campos separados, pero tampoco agregaría 20 campos para el rendimiento.
--actualizar--
la consulta original escrita como
WHERE (Permissions & ( CanWrite | CanModify )) > 0
sería suficiente, sin embargo, parece ser que lo que tienes en la base de datos es un conjunto de atributos que una entidad puede tener. En este caso, la única forma sensata (en términos de bases de datos) de hacerlo es con una relación de uno a muchos con una tabla de atributos.